From 7ae51bf1f14a3af0b9b4c53d03014e04fbb9bfe6 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 11 Oct 2024 16:44:13 -0700 Subject: [PATCH] Add zerocopy support Closes https://github.com/google/zerocopy/issues/1444 --- Cargo.toml | 1 + src/bytes.rs | 23 +++++++++++++++++++++++ src/bytes_mut.rs | 25 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 8083901a1..61497f6db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/bytes.rs b/src/bytes.rs index ec95e802d..a05386c4f 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1448,6 +1448,29 @@ fn _split_to_must_use() {} /// ``` fn _split_off_must_use() {} +#[cfg(feature = "zerocopy")] +mod zerocopy { + use super::*; + + // SAFETY: `::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, `::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 { diff --git a/src/bytes_mut.rs b/src/bytes_mut.rs index ec74c4e97..beda8a69d 100644 --- a/src/bytes_mut.rs +++ b/src/bytes_mut.rs @@ -1880,6 +1880,31 @@ fn _split_off_must_use() {} /// ``` fn _split_must_use() {} +#[cfg(feature = "zerocopy")] +mod zerocopy { + use super::*; + + // SAFETY: `::deref` calls `Bytes::as_slice`, and + // `::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, `::deref` and `::deref_mut` are "stable" in the sense required by + // `ByteSliceMut`'s safety invariant. + unsafe impl ::zerocopy::ByteSlice 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 {