diff --git a/src/bytes.rs b/src/bytes.rs index 2484a1e..9b8e279 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -489,6 +489,8 @@ impl Bytes { self.len = at; + // SAFETY: `at` has been asserted to be <= `self.len()`, and the + // `at == self.len()` and `at == 0` cases were handled above. unsafe { ret.inc_start(at) }; ret @@ -537,6 +539,8 @@ impl Bytes { let mut ret = self.clone(); + // SAFETY: `at` has been asserted to be <= `self.len()`, and the + // `at == self.len()` and `at == 0` cases were handled above. unsafe { self.inc_start(at) }; ret.len = at; diff --git a/src/bytes_mut.rs b/src/bytes_mut.rs index 9c3ee72..689f4b4 100644 --- a/src/bytes_mut.rs +++ b/src/bytes_mut.rs @@ -324,6 +324,10 @@ impl BytesMut { self.capacity(), ); unsafe { + // SAFETY: `shallow_clone` increments the reference count (or + // promotes to shared) and returns a bitwise copy of the handle. + // The caller immediately adjusts both handles so they represent + // disjoint regions. let mut other = self.shallow_clone(); // SAFETY: We've checked that `at` <= `self.capacity()` above. other.advance_unchecked(at); @@ -400,6 +404,10 @@ impl BytesMut { ); unsafe { + // SAFETY: `shallow_clone` increments the reference count (or + // promotes to shared) and returns a bitwise copy of the handle. + // The caller immediately adjusts both handles so they represent + // disjoint regions. let mut other = self.shallow_clone(); // SAFETY: We've checked that `at` <= `self.len()` and we know that `self.len()` <= // `self.capacity()`. diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 255f2af..80835f6 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -1543,6 +1543,65 @@ fn split_to_empty_addr_mut() { let _ = &buf[..]; } +#[test] +fn bytes_mut_split_boundary_capacities() { + // VEC mode + for at in [0, 5, 11] { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"hello world"); + + let other = buf.split_off(at); + assert_eq!( + buf.capacity() + other.capacity(), + 64, + "split_off at {} should preserve total capacity", + at + ); + } + + for at in [0, 5, 11] { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"hello world"); + + let other = buf.split_to(at); + assert_eq!( + buf.capacity() + other.capacity(), + 64, + "split_to at {} should preserve total capacity", + at + ); + } + + // ARC mode (promote via a no-op split) + for at in [0, 5, 11] { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"hello world"); + let _ = buf.split_to(0); // promotes to ARC + + let other = buf.split_off(at); + assert_eq!( + buf.capacity() + other.capacity(), + 64, + "ARC split_off at {} should preserve total capacity", + at + ); + } + + for at in [0, 5, 11] { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"hello world"); + let _ = buf.split_to(0); // promotes to ARC + + let other = buf.split_to(at); + assert_eq!( + buf.capacity() + other.capacity(), + 64, + "ARC split_to at {} should preserve total capacity", + at + ); + } +} + #[derive(Clone)] struct SharedAtomicCounter(Arc);