-
Notifications
You must be signed in to change notification settings - Fork 833
add bytes
conversion
#5111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add bytes
conversion
#5111
Conversation
I'm unsure whether this conversion is a good idea. This implementation makes a full copy of the data every time (both ways) which I think people might not expect. So I'd err on the side of having such conversions be explicit, not implicit. |
See also #1992 |
We could probably avoid copying from Python to Rust by using I'd love it for Python bytes objects to support a similar API where they allow construction from a slice and a destructor, then we could avoid copies both directions. But we're not there yet. |
... so while I think this is probably a useful thing to have, it might be that it's a future useful thing to have? |
I think this can still be useful if python -> rust is non-copy but rust -> bytes is copy, as |
In case it’s not on your radars here, the pyo3-bytes crate does this zero-copy (used by the The approach @davidhewitt suggests above is precisely the way it took:
In that lib a impl<'py> FromPyObject<'py> for PyBytes {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let buffer = ob.extract::<PyBytesWrapper>()?;
let bytes = Bytes::from_owner(buffer);
Ok(Self(bytes))
}
} The /// A wrapper around a PyBuffer that applies a custom destructor that checks if the Python
/// interpreter is still initialized before freeing the buffer memory.
///
/// This also implements AsRef<[u8]> because that is required for Bytes::from_owner
#[derive(Debug)]
struct PyBytesWrapper(Option<PyBuffer<u8>>); |
If I were to make it zero copy Python to Rust, would it still be worth merging and possibly improve to full zero-copy in the future? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I were to make it zero copy Python to Rust...
Can you use the from_owner
constructor mentioned earlier? I'm fine with FromPyObject for Bytes
, but iffy about the other way around.
//! #[pyfunction] | ||
//! fn get_message_bytes() -> Bytes { | ||
//! Bytes::from(b"Hello Python!".to_vec()) | ||
//! } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be more efficient to create a PyBytes
object directly here. This is an example of why I'm not a fan of the Rust to Python conversion.
//! #[pyfunction] | ||
//! fn num_bytes(bytes: Bytes) -> usize { | ||
//! bytes.len() | ||
//! } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example is not that great, the user should just use &[u8]
in this case. Please change the example to something where the Bytes is actually needed.
Add conversions to
bytes::Bytes
crate.This can also help some use cases related to #2888 when trying to deal with
PyBytes
.I would appreciate feedback with regard to
BytesMut
. Currently it gets converted intoPyBytes
, and can be extracted fromPyBytes
andPyByteArray
. This could cause confusion for users who expect a function takingByteMut
to offer a shared mutable buffer between Python and Rust, which cannot exist without a GIL reference. It might also make sense to only offerBytes
as you can always doBytesMut::from(Bytes)
.