diff --git a/src/bytes.rs b/src/bytes.rs index cf398154172c9c450cdd1aed83f0133b04942c78..287ab8874c899a5f80c7c23260cffe76f3987b03 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -804,6 +804,36 @@ impl Bytes { mem::replace(self, result.freeze()); } + + /// Combine splitted Bytes objects back as contiguous. + /// + /// If `Bytes` objects were not contiguous originally, they will be extended. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut buf = Bytes::with_capacity(64); + /// buf.extend_from_slice(b"aaabbbcccddd"); + /// + /// let splitted = buf.split_off(6); + /// assert_eq!(b"aaabbb", &buf[..]); + /// assert_eq!(b"cccddd", &splitted[..]); + /// + /// buf.unsplit(splitted); + /// assert_eq!(b"aaabbbcccddd", &buf[..]); + /// ``` + pub fn unsplit(&mut self, other: Bytes) { + if self.is_empty() { + *self = other; + return; + } + + if let Err(other_inner) = self.inner.try_unsplit(other.inner) { + self.extend_from_slice(other_inner.as_ref()); + } + } } impl IntoBuf for Bytes { @@ -1087,7 +1117,7 @@ impl BytesMut { /// ``` #[inline] pub fn is_empty(&self) -> bool { - self.len() == 0 + self.inner.is_empty() } /// Return true if the `BytesMut` uses inline allocation @@ -1437,32 +1467,13 @@ impl BytesMut { /// assert_eq!(b"aaabbbcccddd", &buf[..]); /// ``` pub fn unsplit(&mut self, other: BytesMut) { - let ptr; - - if other.is_empty() { - return; - } - if self.is_empty() { *self = other; return; } - unsafe { - ptr = self.inner.ptr.offset(self.inner.len as isize); - } - if ptr == other.inner.ptr && - self.inner.kind() == KIND_ARC && - other.inner.kind() == KIND_ARC - { - debug_assert_eq!(self.inner.arc.load(Acquire), - other.inner.arc.load(Acquire)); - // Contiguous blocks, just combine directly - self.inner.len += other.inner.len; - self.inner.cap += other.inner.cap; - } - else { - self.extend_from_slice(&other); + if let Err(other_inner) = self.inner.try_unsplit(other.inner) { + self.extend_from_slice(other_inner.as_ref()); } } } @@ -1922,6 +1933,31 @@ impl Inner { } } + fn try_unsplit(&mut self, other: Inner) -> Result<(), Inner> { + let ptr; + + if other.is_empty() { + return Ok(()); + } + + unsafe { + ptr = self.ptr.offset(self.len as isize); + } + if ptr == other.ptr && + self.kind() == KIND_ARC && + other.kind() == KIND_ARC + { + debug_assert_eq!(self.arc.load(Acquire), + other.arc.load(Acquire)); + // Contiguous blocks, just combine directly + self.len += other.len; + self.cap += other.cap; + Ok(()) + } else { + Err(other) + } + } + unsafe fn set_start(&mut self, start: usize) { // Setting the start to 0 is a no-op, so return early if this is the // case. diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 15c315748367403aad4b81a8fbe258e11c218a3d..c75de1f200bd499f739de0489988165c8162ebfb 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -554,7 +554,141 @@ fn partial_eq_bytesmut() { } #[test] -fn unsplit_basic() { +fn bytes_unsplit_basic() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaabbbcccddd"); + + let splitted = buf.split_off(6); + assert_eq!(b"aaabbb", &buf[..]); + assert_eq!(b"cccddd", &splitted[..]); + + buf.unsplit(splitted); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_empty_other() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaabbbcccddd"); + + // empty other + let other = Bytes::new(); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_empty_self() { + // empty self + let mut buf = Bytes::new(); + + let mut other = Bytes::with_capacity(64); + other.extend_from_slice(b"aaabbbcccddd"); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_inline_arc() { + let mut buf = Bytes::with_capacity(8); //inline + buf.extend_from_slice(b"aaaabbbb"); + + let mut buf2 = Bytes::with_capacity(64); + buf2.extend_from_slice(b"ccccddddeeee"); + + buf2.split_off(8); //arc + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_arc_inline() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeee"); + + buf.split_off(8); //arc + + let mut buf2 = Bytes::with_capacity(8); //inline + buf2.extend_from_slice(b"ccccdddd"); + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); + +} + +#[test] +fn bytes_unsplit_both_inline() { + let mut buf = Bytes::with_capacity(16); //inline + buf.extend_from_slice(b"aaaabbbbccccdddd"); + + let splitted = buf.split_off(8); // both inline + assert_eq!(b"aaaabbbb", &buf[..]); + assert_eq!(b"ccccdddd", &splitted[..]); + + buf.unsplit(splitted); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + + +#[test] +fn bytes_unsplit_arc_different() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeee"); + + buf.split_off(8); //arc + + let mut buf2 = Bytes::with_capacity(64); + buf2.extend_from_slice(b"ccccddddeeee"); + + buf2.split_off(8); //arc + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_arc_non_contiguous() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeeeccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + + let buf3 = buf2.split_off(4); //arc + + buf.unsplit(buf3); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_two_split_offs() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + let buf3 = buf2.split_off(4); //arc + + buf2.unsplit(buf3); + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_overlapping_references() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"abcdefghijklmnopqrstuvwxyz"); + let mut buf0010 = buf.slice(0, 10); + let buf1020 = buf.slice(10, 20); + let buf0515 = buf.slice(5, 15); + buf0010.unsplit(buf1020); + assert_eq!(b"abcdefghijklmnopqrst", &buf0010[..]); + assert_eq!(b"fghijklmno", &buf0515[..]); +} + +#[test] +fn bytes_mut_unsplit_basic() { let mut buf = BytesMut::with_capacity(64); buf.extend_from_slice(b"aaabbbcccddd"); @@ -567,7 +701,7 @@ fn unsplit_basic() { } #[test] -fn unsplit_empty_other() { +fn bytes_mut_unsplit_empty_other() { let mut buf = BytesMut::with_capacity(64); buf.extend_from_slice(b"aaabbbcccddd"); @@ -579,7 +713,7 @@ fn unsplit_empty_other() { } #[test] -fn unsplit_empty_self() { +fn bytes_mut_unsplit_empty_self() { // empty self let mut buf = BytesMut::new(); @@ -591,7 +725,7 @@ fn unsplit_empty_self() { } #[test] -fn unsplit_inline_arc() { +fn bytes_mut_unsplit_inline_arc() { let mut buf = BytesMut::with_capacity(8); //inline buf.extend_from_slice(b"aaaabbbb"); @@ -605,7 +739,7 @@ fn unsplit_inline_arc() { } #[test] -fn unsplit_arc_inline() { +fn bytes_mut_unsplit_arc_inline() { let mut buf = BytesMut::with_capacity(64); buf.extend_from_slice(b"aaaabbbbeeee"); @@ -620,7 +754,7 @@ fn unsplit_arc_inline() { } #[test] -fn unsplit_both_inline() { +fn bytes_mut_unsplit_both_inline() { let mut buf = BytesMut::with_capacity(16); //inline buf.extend_from_slice(b"aaaabbbbccccdddd"); @@ -634,7 +768,7 @@ fn unsplit_both_inline() { #[test] -fn unsplit_arc_different() { +fn bytes_mut_unsplit_arc_different() { let mut buf = BytesMut::with_capacity(64); buf.extend_from_slice(b"aaaabbbbeeee"); @@ -650,7 +784,7 @@ fn unsplit_arc_different() { } #[test] -fn unsplit_arc_non_contiguous() { +fn bytes_mut_unsplit_arc_non_contiguous() { let mut buf = BytesMut::with_capacity(64); buf.extend_from_slice(b"aaaabbbbeeeeccccdddd"); @@ -663,7 +797,7 @@ fn unsplit_arc_non_contiguous() { } #[test] -fn unsplit_two_split_offs() { +fn bytes_mut_unsplit_two_split_offs() { let mut buf = BytesMut::with_capacity(64); buf.extend_from_slice(b"aaaabbbbccccdddd");