diff --git a/src/bytes.rs b/src/bytes.rs index bbd7bdc..aed4d7c 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -567,7 +567,9 @@ impl Bytes { /// ``` #[inline] pub fn truncate(&mut self, len: usize) { - if len < self.len { + if len == 0 { + drop(mem::replace(self, Bytes::new_empty_with_ptr(self.ptr))); + } else if len < self.len { // The Vec "promotable" vtables do not store the capacity, // so we cannot truncate while using this repr. We *have* to // promote using `split_off` so the capacity can be stored. diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 80835f6..5d01b5b 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -339,6 +339,31 @@ fn truncate() { assert_eq!(hello, "hello"); } +#[test] +fn truncate_to_zero_releases_shared_reference() { + let mut bytes = BytesMut::from(&b"hello"[..]); + drop(bytes.split_off(bytes.len())); + let mut truncated = bytes.freeze(); + let remaining = truncated.clone(); + + truncated.truncate(0); + + assert!(truncated.is_empty()); + let mut remaining = remaining.try_into_mut().unwrap(); + remaining[0] = b'H'; + assert_eq!(remaining, b"Hello"[..]); + + let mut bytes = BytesMut::from(&b"hello"[..]); + drop(bytes.split_off(bytes.len())); + let mut nonempty = bytes.freeze(); + let remaining = nonempty.clone(); + + nonempty.truncate(1); + + assert_eq!(nonempty, b"h"[..]); + assert!(remaining.try_into_mut().is_err()); +} + #[test] fn freeze_clone_shared() { let s = &b"abcdefgh"[..];