Skip to content

Commit

Permalink
return self from update and update_mmap
Browse files Browse the repository at this point in the history
  • Loading branch information
oconnor663 committed Feb 4, 2024
1 parent 3ffe734 commit 796b54c
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 23 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ hasher.update(b"baz")
hash2 = hasher.digest()
assert hash1 == hash2

# Hash the same input fluently.
assert hash1 == blake3(b"foo").update(b"bar").update(b"baz").digest()

# Hexadecimal output.
print("The hash of 'hello world' is", blake3(b"hello world").hexdigest())

Expand Down
4 changes: 2 additions & 2 deletions blake3.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class blake3:
usedforsecurity: bool = ...,
): ...
# TODO: use collections.abc.Buffer here when PEP 688 lands in Python 3.12
def update(self, data: bytes, /) -> None: ...
def update_mmap(self, path: str | PathLike[str]) -> None: ...
def update(self, data: bytes, /) -> blake3: ...
def update_mmap(self, path: str | PathLike[str]) -> blake3: ...
def copy(self) -> blake3: ...
def reset(self) -> None: ...
def digest(self, length: int = ..., *, seek: int = ...) -> bytes: ...
Expand Down
7 changes: 2 additions & 5 deletions c_impl/blake3module.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,7 @@ static PyObject *Blake3_update(Blake3Object *self, PyObject *args) {
}

// success
Py_INCREF(Py_None);
ret = Py_None;
ret = self;

exit:
release_buf_if_acquired(&data);
Expand Down Expand Up @@ -268,9 +267,7 @@ static PyObject *Blake3_update_mmap(Blake3Object *self, PyObject *args,
goto exit;
}

// success
Py_INCREF(Py_None);
ret = Py_None;
ret = self;

exit:
if (file) {
Expand Down
42 changes: 30 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,21 +297,26 @@ impl Blake3Class {
/// Arguments:
/// - `data` (required): The input bytes.
#[pyo3(signature=(data, /))]
fn update(&mut self, py: Python, data: &PyAny) -> PyResult<()> {
fn update<'this>(
mut this: PyRefMut<'this, Self>,
py: Python,
data: &PyAny,
) -> PyResult<PyRefMut<'this, Self>> {
// Get a slice that's not tied to the `py` lifetime.
// XXX: The safety situation here is a bit complicated. See all the
// comments in unsafe_slice_from_buffer.
let slice: &[u8] = unsafe { unsafe_slice_from_buffer(py, data)? };

let mut update_closure = || match &mut self.threading_mode {
let this_mut = &mut *this;
let mut update_closure = || match &mut this_mut.threading_mode {
ThreadingMode::Single => {
self.rust_hasher.lock().unwrap().update(slice);
this_mut.rust_hasher.lock().unwrap().update(slice);
}
ThreadingMode::Auto => {
self.rust_hasher.lock().unwrap().update_rayon(slice);
this_mut.rust_hasher.lock().unwrap().update_rayon(slice);
}
ThreadingMode::Pool { pool, .. } => pool.install(|| {
self.rust_hasher.lock().unwrap().update_rayon(slice);
this_mut.rust_hasher.lock().unwrap().update_rayon(slice);
}),
};

Expand All @@ -325,7 +330,7 @@ impl Blake3Class {
update_closure();
}

Ok(())
Ok(this)
}

/// Read a file using memory mapping and add its bytes to the hasher. You can call this any
Expand All @@ -334,25 +339,38 @@ impl Blake3Class {
/// Arguments:
/// - `path` (required): The filepath to read.
#[pyo3(signature=(path))]
fn update_mmap(&mut self, py: Python, path: PathBuf) -> PyResult<()> {
fn update_mmap<'this>(
mut this: PyRefMut<'this, Self>,
py: Python,
path: PathBuf,
) -> PyResult<PyRefMut<'this, Self>> {
let this_mut = &mut *this;
py.allow_threads(|| -> PyResult<()> {
match &mut self.threading_mode {
match &mut this_mut.threading_mode {
ThreadingMode::Single => {
self.rust_hasher.lock().unwrap().update_mmap(&path)?;
this_mut.rust_hasher.lock().unwrap().update_mmap(&path)?;
}
ThreadingMode::Auto => {
self.rust_hasher.lock().unwrap().update_mmap_rayon(&path)?;
this_mut
.rust_hasher
.lock()
.unwrap()
.update_mmap_rayon(&path)?;
}
ThreadingMode::Pool { pool, .. } => {
pool.install(|| -> PyResult<()> {
self.rust_hasher.lock().unwrap().update_mmap_rayon(&path)?;
this_mut
.rust_hasher
.lock()
.unwrap()
.update_mmap_rayon(&path)?;
Ok(())
})?;
}
}
Ok(())
})?;
Ok(())
Ok(this)
}

/// Return a copy (“clone”) of the hasher. This can be used to
Expand Down
12 changes: 8 additions & 4 deletions tests/test_blake3.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,14 @@ def test_mmap() -> None:
hasher2.update_mmap(Path(temp_path))
assert blake3(input_bytes).digest() == hasher2.digest()

hasher3 = blake3(max_threads=4)
hasher3.update_mmap(temp_path)
hasher3.update_mmap(path=Path(temp_path))
assert blake3(2 * input_bytes).digest() == hasher3.digest()
# Also test that update and update_mmap return self.
hasher3 = (
blake3(max_threads=4)
.update(input_bytes)
.update_mmap(temp_path)
.update_mmap(path=Path(temp_path))
)
assert blake3(3 * input_bytes).digest() == hasher3.digest()

# Test a nonexistent file.
try:
Expand Down

0 comments on commit 796b54c

Please sign in to comment.