Skip to content

Commit

Permalink
Add zerocopy support
Browse files Browse the repository at this point in the history
  • Loading branch information
joshlf committed Oct 11, 2024
1 parent d7c1d65 commit e08f711
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ std = []

[dependencies]
serde = { version = "1.0.60", optional = true, default-features = false, features = ["alloc"] }
zerocopy = { version = "0.8.5", optional = true, default-features = false }

[dev-dependencies]
serde_test = "1.0"
Expand Down
23 changes: 23 additions & 0 deletions src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,29 @@ fn _split_to_must_use() {}
/// ```
fn _split_off_must_use() {}

#[cfg(feature = "zerocopy")]
mod zerocopy {
use super::*;

// SAFETY: `<Bytes as Deref>::deref` calls `Bytes::as_slice`, which
// constructs its return value from the `ptr` and `len` fields. Neither of
// these fields are modified by any methods on `ByteSlice` or its
// super-traits (namely, `Deref::deref`). `Bytes` does not implement
// `ByteSliceMut`, `IntoByteSlice`, or `IntoByteSliceMut`. Thus, `<Bytes as
// Deref>::deref` is "stable" in the sense required by `ByteSlice`'s safety
// invariant.
unsafe impl ::zerocopy::ByteSlice for Bytes {}
// SAFETY: `split_at_unchecked` is implemented in terms of
// `Bytes::split_off`, which is implemented as required by
// `SplitByteSlice`'s safety invariant.
unsafe impl ::zerocopy::SplitByteSlice for Bytes {
unsafe fn split_at_unchecked(mut self, mid: usize) -> (Bytes, Bytes) {
let tail = self.split_off(mid);
(self, tail)
}
}
}

// fuzz tests
#[cfg(all(test, loom))]
mod fuzz {
Expand Down
26 changes: 26 additions & 0 deletions src/bytes_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,32 @@ fn _split_off_must_use() {}
/// ```
fn _split_must_use() {}

#[cfg(feature = "zerocopy")]
mod zerocopy {
use super::*;

// SAFETY: `<BytesMut as Deref>::deref` calls `Bytes::as_slice`, and
// `<BytesMut as DerefMut>::deref_mut` calls `Bytes::as_slice_mut`, both of
// which construct their return values from the `ptr` and `len` fields.
// Neither of these fields are modified by any methods on `ByteSlice`,
// `ByteSliceMut`, or their super-traits (namely, `Deref::deref` and
// `DerefMut::deref_mut`). `Bytes` does not implement `IntoByteSlice` or
// `IntoByteSliceMut`. Thus, `<Bytes as Deref>::deref` and `<BytesMut as
// DerefMut>::deref_mut` are "stable" in the sense required by
// `ByteSliceMut`'s safety invariant.
unsafe impl ::zerocopy::ByteSlice for BytesMut {}
unsafe impl ::zerocopy::CloneableByteSlice for BytesMut {}
// SAFETY: `split_at_unchecked` is implemented in terms of
// `BytesMut::split_off`, which is implemented as required by
// `SplitByteSlice`'s safety invariant.
unsafe impl ::zerocopy::SplitByteSlice for BytesMut {
unsafe fn split_at_unchecked(mut self, mid: usize) -> (BytesMut, BytesMut) {
let tail = self.split_off(mid);
(self, tail)
}
}
}

// fuzz tests
#[cfg(all(test, loom))]
mod fuzz {
Expand Down

0 comments on commit e08f711

Please sign in to comment.