From 12f62b94d6ccdca90dcd0edfbff82031fec3912f Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Wed, 22 Sep 2021 10:51:41 -0700 Subject: Upgrade rust/crates/bytes to 1.1.0 Test: make Change-Id: I62c795247b1a9f37ec66c3ef6b1add6b78530482 --- .cargo_vcs_info.json | 2 +- .github/workflows/ci.yml | 6 ++-- Android.bp | 2 ++ CHANGELOG.md | 23 ++++++++++++++- Cargo.toml | 7 +++-- Cargo.toml.orig | 12 ++++---- METADATA | 8 ++--- ci/test-stable.sh | 3 +- src/buf/buf_impl.rs | 3 ++ src/buf/buf_mut.rs | 77 +++++++++++++++++++++++++++++++++++++++++++----- src/buf/chain.rs | 27 +++++++++++++++-- src/buf/take.rs | 12 ++++++-- src/buf/uninit_slice.rs | 7 +++++ src/bytes.rs | 12 ++++++-- src/bytes_mut.rs | 21 +++++++++++-- src/lib.rs | 1 - tests/test_buf_mut.rs | 53 +++++++++++++++++++++++++++++++-- tests/test_bytes.rs | 41 ++++++++++++++++++++++++++ tests/test_chain.rs | 21 +++++++++++++ tests/test_take.rs | 20 +++++++++++++ 20 files changed, 320 insertions(+), 38 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 8a97d76..64b65d2 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "7b18c1c076adf9dff4dca28ffc1bbd8759860798" + "sha1": "ebc61e5af14cd9b436ba880cf19e849b05a04c29" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc03588..00a4414 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ on: env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 - nightly: nightly-2020-12-17 + nightly: nightly-2021-04-13 defaults: run: @@ -94,7 +94,7 @@ jobs: - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu - wasm32-unknown-unknown - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Rust @@ -160,6 +160,8 @@ jobs: run: rustup update stable && rustup default stable - name: Build documentation run: cargo doc --no-deps --all-features + env: + RUSTDOCFLAGS: --cfg docsrs - name: Publish documentation run: | cd target/doc diff --git a/Android.bp b/Android.bp index 4d22da0..1355891 100644 --- a/Android.bp +++ b/Android.bp @@ -22,6 +22,8 @@ rust_library { name: "libbytes", host_supported: true, crate_name: "bytes", + cargo_env_compat: true, + cargo_pkg_version: "1.1.0", srcs: ["src/lib.rs"], edition: "2018", features: [ diff --git a/CHANGELOG.md b/CHANGELOG.md index a53a165..636d36b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +# 1.1.0 (August 25, 2021) + +### Added + +- `BufMut::put_bytes(self, val, cnt)` (#487) +- Implement `From>` for `Bytes` (#504) + +### Changed + +- Override `put_slice` for `&mut [u8]` (#483) +- Panic on integer overflow in `Chain::remaining` (#482) +- Add inline tags to `UninitSlice` methods (#443) +- Override `copy_to_bytes` for Chain and Take (#481) +- Keep capacity when unsplit on empty other buf (#502) + +### Documented + +- Clarify `BufMut` allocation guarantees (#501) +- Clarify `BufMut::put_int` behavior (#486) +- Clarify actions of `clear` and `truncate`. (#508) + # 1.0.1 (January 11, 2021) ### Changed @@ -10,7 +31,7 @@ # 1.0.0 (December 22, 2020) ### Changed -- Rename Buf/BufMut, methods to chunk/chunk_mut (#450) +- Rename `Buf`/`BufMut` methods `bytes()` and `bytes_mut()` to `chunk()` and `chunk_mut()` (#450) ### Removed - remove unused Buf implementation. (#449) diff --git a/Cargo.toml b/Cargo.toml index d102cf0..065f0f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,15 +13,16 @@ [package] edition = "2018" name = "bytes" -version = "1.0.1" +version = "1.1.0" authors = ["Carl Lerche ", "Sean McArthur "] description = "Types and traits for working with bytes" -documentation = "https://docs.rs/bytes/1.0.1/bytes/" readme = "README.md" keywords = ["buffers", "zero-copy", "io"] categories = ["network-programming", "data-structures"] license = "MIT" repository = "https://github.com/tokio-rs/bytes" +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] [dependencies.serde] version = "1.0.60" features = ["alloc"] @@ -34,4 +35,4 @@ version = "1.0" default = ["std"] std = [] [target."cfg(loom)".dev-dependencies.loom] -version = "0.4" +version = "0.5" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 8f4e224..2b7e32b 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -2,18 +2,15 @@ name = "bytes" # When releasing to crates.io: -# - Update html_root_url. # - Update CHANGELOG.md. -# - Update doc URL. -# - Create "v1.0.x" git tag. -version = "1.0.1" +# - Create "v1.x.y" git tag. +version = "1.1.0" license = "MIT" authors = [ "Carl Lerche ", "Sean McArthur ", ] description = "Types and traits for working with bytes" -documentation = "https://docs.rs/bytes/1.0.1/bytes/" repository = "https://github.com/tokio-rs/bytes" readme = "README.md" keywords = ["buffers", "zero-copy", "io"] @@ -31,4 +28,7 @@ serde = { version = "1.0.60", optional = true, default-features = false, feature serde_test = "1.0" [target.'cfg(loom)'.dev-dependencies] -loom = "0.4" +loom = "0.5" + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] diff --git a/METADATA b/METADATA index 9c2bf5a..6723e08 100644 --- a/METADATA +++ b/METADATA @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/bytes/bytes-1.0.1.crate" + value: "https://static.crates.io/crates/bytes/bytes-1.1.0.crate" } - version: "1.0.1" + version: "1.1.0" license_type: NOTICE last_upgrade_date { year: 2021 - month: 1 - day: 11 + month: 9 + day: 22 } } diff --git a/ci/test-stable.sh b/ci/test-stable.sh index 01a32f5..4421f3a 100644 --- a/ci/test-stable.sh +++ b/ci/test-stable.sh @@ -5,7 +5,8 @@ set -ex cmd="${1:-test}" # Install cargo-hack for feature flag test -cargo install cargo-hack +host=$(rustc -Vv | grep host | sed 's/host: //') +curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-$host.tar.gz | tar xzf - -C ~/.cargo/bin # Run with each feature # * --each-feature includes both default/no-default features diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs index 16ad8a7..a33c8a4 100644 --- a/src/buf/buf_impl.rs +++ b/src/buf/buf_impl.rs @@ -127,6 +127,9 @@ pub trait Buf { /// This function should never panic. Once the end of the buffer is reached, /// i.e., `Buf::remaining` returns 0, calls to `chunk()` should return an /// empty slice. + // The `chunk` method was previously called `bytes`. This alias makes the rename + // more easily discoverable. + #[cfg_attr(docsrs, doc(alias = "bytes"))] fn chunk(&self) -> &[u8]; /// Fills `dst` with potentially multiple slices starting at `self`'s diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index f736727..4c2bd2c 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -33,6 +33,10 @@ pub unsafe trait BufMut { /// This value is greater than or equal to the length of the slice returned /// by `chunk_mut()`. /// + /// Writing to a `BufMut` may involve allocating more memory on the fly. + /// Implementations may fail before reaching the number of bytes indicated + /// by this method if they encounter an allocation failure. + /// /// # Examples /// /// ``` @@ -158,6 +162,12 @@ pub unsafe trait BufMut { /// `chunk_mut()` returning an empty slice implies that `remaining_mut()` will /// return 0 and `remaining_mut()` returning 0 implies that `chunk_mut()` will /// return an empty slice. + /// + /// This function may trigger an out-of-memory abort if it tries to allocate + /// memory and fails to do so. + // The `chunk_mut` method was previously called `bytes_mut`. This alias makes the + // rename more easily discoverable. + #[cfg_attr(docsrs, doc(alias = "bytes_mut"))] fn chunk_mut(&mut self) -> &mut UninitSlice; /// Transfer bytes into `self` from `src` and advance the cursor by the @@ -251,6 +261,37 @@ pub unsafe trait BufMut { } } + /// Put `cnt` bytes `val` into `self`. + /// + /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster. + /// + /// `self` must have at least `cnt` remaining capacity. + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut dst = [0; 6]; + /// + /// { + /// let mut buf = &mut dst[..]; + /// buf.put_bytes(b'a', 4); + /// + /// assert_eq!(2, buf.remaining_mut()); + /// } + /// + /// assert_eq!(b"aaaa\0\0", &dst); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_bytes(&mut self, val: u8, cnt: usize) { + for _ in 0..cnt { + self.put_u8(val); + } + } + /// Writes an unsigned 8 bit integer to `self`. /// /// The current position is advanced by 1. @@ -693,7 +734,7 @@ pub unsafe trait BufMut { self.put_slice(&n.to_le_bytes()[0..nbytes]); } - /// Writes a signed n-byte integer to `self` in big-endian byte order. + /// Writes low `nbytes` of a signed integer to `self` in big-endian byte order. /// /// The current position is advanced by `nbytes`. /// @@ -703,19 +744,19 @@ pub unsafe trait BufMut { /// use bytes::BufMut; /// /// let mut buf = vec![]; - /// buf.put_int(0x010203, 3); + /// buf.put_int(0x0504010203, 3); /// assert_eq!(buf, b"\x01\x02\x03"); /// ``` /// /// # Panics /// /// This function panics if there is not enough remaining capacity in - /// `self`. + /// `self` or if `nbytes` is greater than 8. fn put_int(&mut self, n: i64, nbytes: usize) { self.put_slice(&n.to_be_bytes()[mem::size_of_val(&n) - nbytes..]); } - /// Writes a signed n-byte integer to `self` in little-endian byte order. + /// Writes low `nbytes` of a signed integer to `self` in little-endian byte order. /// /// The current position is advanced by `nbytes`. /// @@ -725,14 +766,14 @@ pub unsafe trait BufMut { /// use bytes::BufMut; /// /// let mut buf = vec![]; - /// buf.put_int_le(0x010203, 3); + /// buf.put_int_le(0x0504010203, 3); /// assert_eq!(buf, b"\x03\x02\x01"); /// ``` /// /// # Panics /// /// This function panics if there is not enough remaining capacity in - /// `self`. + /// `self` or if `nbytes` is greater than 8. fn put_int_le(&mut self, n: i64, nbytes: usize) { self.put_slice(&n.to_le_bytes()[0..nbytes]); } @@ -1009,12 +1050,29 @@ unsafe impl BufMut for &mut [u8] { let (_, b) = core::mem::replace(self, &mut []).split_at_mut(cnt); *self = b; } + + #[inline] + fn put_slice(&mut self, src: &[u8]) { + self[..src.len()].copy_from_slice(src); + unsafe { + self.advance_mut(src.len()); + } + } + + fn put_bytes(&mut self, val: u8, cnt: usize) { + assert!(self.remaining_mut() >= cnt); + unsafe { + ptr::write_bytes(self.as_mut_ptr(), val, cnt); + self.advance_mut(cnt); + } + } } unsafe impl BufMut for Vec { #[inline] fn remaining_mut(&self) -> usize { - usize::MAX - self.len() + // A vector can never have more than isize::MAX bytes + core::isize::MAX as usize - self.len() } #[inline] @@ -1072,6 +1130,11 @@ unsafe impl BufMut for Vec { fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } + + fn put_bytes(&mut self, val: u8, cnt: usize) { + let new_len = self.len().checked_add(cnt).unwrap(); + self.resize(new_len, val); + } } // The existence of this function makes the compiler catch if the BufMut diff --git a/src/buf/chain.rs b/src/buf/chain.rs index d68bc2d..9ce5f23 100644 --- a/src/buf/chain.rs +++ b/src/buf/chain.rs @@ -1,5 +1,5 @@ use crate::buf::{IntoIter, UninitSlice}; -use crate::{Buf, BufMut}; +use crate::{Buf, BufMut, Bytes}; #[cfg(feature = "std")] use std::io::IoSlice; @@ -135,7 +135,7 @@ where U: Buf, { fn remaining(&self) -> usize { - self.a.remaining() + self.b.remaining() + self.a.remaining().checked_add(self.b.remaining()).unwrap() } fn chunk(&self) -> &[u8] { @@ -170,6 +170,24 @@ where n += self.b.chunks_vectored(&mut dst[n..]); n } + + fn copy_to_bytes(&mut self, len: usize) -> Bytes { + let a_rem = self.a.remaining(); + if a_rem >= len { + self.a.copy_to_bytes(len) + } else if a_rem == 0 { + self.b.copy_to_bytes(len) + } else { + assert!( + len - a_rem <= self.b.remaining(), + "`len` greater than remaining" + ); + let mut ret = crate::BytesMut::with_capacity(len); + ret.put(&mut self.a); + ret.put((&mut self.b).take(len - a_rem)); + ret.freeze() + } + } } unsafe impl BufMut for Chain @@ -178,7 +196,10 @@ where U: BufMut, { fn remaining_mut(&self) -> usize { - self.a.remaining_mut() + self.b.remaining_mut() + self.a + .remaining_mut() + .checked_add(self.b.remaining_mut()) + .unwrap() } fn chunk_mut(&mut self) -> &mut UninitSlice { diff --git a/src/buf/take.rs b/src/buf/take.rs index 1747f6e..d3cb10a 100644 --- a/src/buf/take.rs +++ b/src/buf/take.rs @@ -1,11 +1,11 @@ -use crate::Buf; +use crate::{Buf, Bytes}; use core::cmp; /// A `Buf` adapter which limits the bytes read from an underlying buffer. /// /// This struct is generally created by calling `take()` on `Buf`. See -/// documentation of [`take()`](trait.BufExt.html#method.take) for more details. +/// documentation of [`take()`](trait.Buf.html#method.take) for more details. #[derive(Debug)] pub struct Take { inner: T, @@ -144,4 +144,12 @@ impl Buf for Take { self.inner.advance(cnt); self.limit -= cnt; } + + fn copy_to_bytes(&mut self, len: usize) -> Bytes { + assert!(len <= self.remaining(), "`len` greater than remaining"); + + let r = self.inner.copy_to_bytes(len); + self.limit -= len; + r + } } diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 73f4e89..fb67c0a 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -40,6 +40,7 @@ impl UninitSlice { /// /// let slice = unsafe { UninitSlice::from_raw_parts_mut(ptr, len) }; /// ``` + #[inline] pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { let maybe_init: &mut [MaybeUninit] = core::slice::from_raw_parts_mut(ptr as *mut _, len); @@ -64,6 +65,7 @@ impl UninitSlice { /// /// assert_eq!(b"boo", &data[..]); /// ``` + #[inline] pub fn write_byte(&mut self, index: usize, byte: u8) { assert!(index < self.len()); @@ -90,6 +92,7 @@ impl UninitSlice { /// /// assert_eq!(b"bar", &data[..]); /// ``` + #[inline] pub fn copy_from_slice(&mut self, src: &[u8]) { use core::ptr; @@ -116,6 +119,7 @@ impl UninitSlice { /// let mut slice = &mut data[..]; /// let ptr = BufMut::chunk_mut(&mut slice).as_mut_ptr(); /// ``` + #[inline] pub fn as_mut_ptr(&mut self) -> *mut u8 { self.0.as_mut_ptr() as *mut _ } @@ -133,6 +137,7 @@ impl UninitSlice { /// /// assert_eq!(len, 3); /// ``` + #[inline] pub fn len(&self) -> usize { self.0.len() } @@ -150,6 +155,7 @@ macro_rules! impl_index { impl Index<$t> for UninitSlice { type Output = UninitSlice; + #[inline] fn index(&self, index: $t) -> &UninitSlice { let maybe_uninit: &[MaybeUninit] = &self.0[index]; unsafe { &*(maybe_uninit as *const [MaybeUninit] as *const UninitSlice) } @@ -157,6 +163,7 @@ macro_rules! impl_index { } impl IndexMut<$t> for UninitSlice { + #[inline] fn index_mut(&mut self, index: $t) -> &mut UninitSlice { let maybe_uninit: &mut [MaybeUninit] = &mut self.0[index]; unsafe { &mut *(maybe_uninit as *mut [MaybeUninit] as *mut UninitSlice) } diff --git a/src/bytes.rs b/src/bytes.rs index b1b35ea..d0be0d2 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -797,14 +797,20 @@ impl From<&'static str> for Bytes { impl From> for Bytes { fn from(vec: Vec) -> Bytes { - // into_boxed_slice doesn't return a heap allocation for empty vectors, + let slice = vec.into_boxed_slice(); + slice.into() + } +} + +impl From> for Bytes { + fn from(slice: Box<[u8]>) -> Bytes { + // Box<[u8]> doesn't contain a heap allocation for empty slices, // so the pointer isn't aligned enough for the KIND_VEC stashing to // work. - if vec.is_empty() { + if slice.is_empty() { return Bytes::new(); } - let slice = vec.into_boxed_slice(); let len = slice.len(); let ptr = Box::into_raw(slice) as *mut u8; diff --git a/src/bytes_mut.rs b/src/bytes_mut.rs index 61c0460..147484d 100644 --- a/src/bytes_mut.rs +++ b/src/bytes_mut.rs @@ -380,6 +380,8 @@ impl BytesMut { /// If `len` is greater than the buffer's current length, this has no /// effect. /// + /// Existing underlying capacity is preserved. + /// /// The [`split_off`] method can emulate `truncate`, but this causes the /// excess bytes to be returned instead of dropped. /// @@ -402,7 +404,7 @@ impl BytesMut { } } - /// Clears the buffer, removing all data. + /// Clears the buffer, removing all data. Existing capacity is preserved. /// /// # Examples /// @@ -819,7 +821,7 @@ impl BytesMut { } fn try_unsplit(&mut self, other: BytesMut) -> Result<(), BytesMut> { - if other.is_empty() { + if other.capacity() == 0 { return Ok(()); } @@ -1010,6 +1012,19 @@ unsafe impl BufMut for BytesMut { fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } + + fn put_bytes(&mut self, val: u8, cnt: usize) { + self.reserve(cnt); + unsafe { + let dst = self.uninit_slice(); + // Reserved above + debug_assert!(dst.len() >= cnt); + + ptr::write_bytes(dst.as_mut_ptr(), val, cnt); + + self.advance_mut(cnt); + } + } } impl AsRef<[u8]> for BytesMut { @@ -1250,6 +1265,7 @@ impl Shared { } } +#[inline] fn original_capacity_to_repr(cap: usize) -> usize { let width = PTR_WIDTH - ((cap >> MIN_ORIGINAL_CAPACITY_WIDTH).leading_zeros() as usize); cmp::min( @@ -1476,6 +1492,7 @@ impl PartialEq for BytesMut { } } +#[inline] fn vptr(ptr: *mut u8) -> NonNull { if cfg!(debug_assertions) { NonNull::new(ptr).expect("Vec pointer should be non-null") diff --git a/src/lib.rs b/src/lib.rs index dd8cc96..706735e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ no_crate_inject, attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) ))] -#![doc(html_root_url = "https://docs.rs/bytes/1.0.1")] #![no_std] //! Provides abstractions for working with bytes. diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index 8d270e3..53f4e86 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -9,7 +9,7 @@ use core::usize; fn test_vec_as_mut_buf() { let mut buf = Vec::with_capacity(64); - assert_eq!(buf.remaining_mut(), usize::MAX); + assert_eq!(buf.remaining_mut(), isize::MAX as usize); assert!(buf.chunk_mut().len() >= 64); @@ -17,7 +17,7 @@ fn test_vec_as_mut_buf() { assert_eq!(&buf, b"zomg"); - assert_eq!(buf.remaining_mut(), usize::MAX - 4); + assert_eq!(buf.remaining_mut(), isize::MAX as usize - 4); assert_eq!(buf.capacity(), 64); for _ in 0..16 { @@ -27,6 +27,14 @@ fn test_vec_as_mut_buf() { assert_eq!(buf.len(), 68); } +#[test] +fn test_vec_put_bytes() { + let mut buf = Vec::new(); + buf.push(17); + buf.put_bytes(19, 2); + assert_eq!([17, 19, 19], &buf[..]); +} + #[test] fn test_put_u8() { let mut buf = Vec::with_capacity(8); @@ -45,6 +53,34 @@ fn test_put_u16() { assert_eq!(b"\x54\x21", &buf[..]); } +#[test] +fn test_put_int() { + let mut buf = Vec::with_capacity(8); + buf.put_int(0x1020304050607080, 3); + assert_eq!(b"\x60\x70\x80", &buf[..]); +} + +#[test] +#[should_panic] +fn test_put_int_nbytes_overflow() { + let mut buf = Vec::with_capacity(8); + buf.put_int(0x1020304050607080, 9); +} + +#[test] +fn test_put_int_le() { + let mut buf = Vec::with_capacity(8); + buf.put_int_le(0x1020304050607080, 3); + assert_eq!(b"\x80\x70\x60", &buf[..]); +} + +#[test] +#[should_panic] +fn test_put_int_le_nbytes_overflow() { + let mut buf = Vec::with_capacity(8); + buf.put_int_le(0x1020304050607080, 9); +} + #[test] #[should_panic(expected = "cannot advance")] fn test_vec_advance_mut() { @@ -70,6 +106,19 @@ fn test_mut_slice() { let mut v = vec![0, 0, 0, 0]; let mut s = &mut v[..]; s.put_u32(42); + + assert_eq!(s.len(), 0); + assert_eq!(&v, &[0, 0, 0, 42]); +} + +#[test] +fn test_slice_put_bytes() { + let mut v = [0, 0, 0, 0]; + let mut s = &mut v[..]; + s.put_u8(17); + s.put_bytes(19, 2); + assert_eq!(1, s.remaining_mut()); + assert_eq!(&[17, 19, 19, 0], &v[..]); } #[test] diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index b9e6ce4..f0cae99 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -784,6 +784,31 @@ fn bytes_mut_unsplit_empty_self() { assert_eq!(b"aaabbbcccddd", &buf[..]); } +#[test] +fn bytes_mut_unsplit_other_keeps_capacity() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aabb"); + + // non empty other created "from" buf + let mut other = buf.split_off(buf.len()); + other.extend_from_slice(b"ccddee"); + buf.unsplit(other); + + assert_eq!(buf.capacity(), 64); +} + +#[test] +fn bytes_mut_unsplit_empty_other_keeps_capacity() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aabbccddee"); + + // empty other created "from" buf + let other = buf.split_off(buf.len()); + buf.unsplit(other); + + assert_eq!(buf.capacity(), 64); +} + #[test] fn bytes_mut_unsplit_arc_different() { let mut buf = BytesMut::with_capacity(64); @@ -961,3 +986,19 @@ fn bytes_with_capacity_but_empty() { let vec = Vec::with_capacity(1); let _ = Bytes::from(vec); } + +#[test] +fn bytes_put_bytes() { + let mut bytes = BytesMut::new(); + bytes.put_u8(17); + bytes.put_bytes(19, 2); + assert_eq!([17, 19, 19], bytes.as_ref()); +} + +#[test] +fn box_slice_empty() { + // See https://github.com/tokio-rs/bytes/issues/340 + let empty: Box<[u8]> = Default::default(); + let b = Bytes::from(empty); + assert!(b.is_empty()); +} diff --git a/tests/test_chain.rs b/tests/test_chain.rs index 500ccd4..affaf7a 100644 --- a/tests/test_chain.rs +++ b/tests/test_chain.rs @@ -132,3 +132,24 @@ fn vectored_read() { assert_eq!(iovecs[3][..], b""[..]); } } + +#[test] +fn chain_get_bytes() { + let mut ab = Bytes::copy_from_slice(b"ab"); + let mut cd = Bytes::copy_from_slice(b"cd"); + let ab_ptr = ab.as_ptr(); + let cd_ptr = cd.as_ptr(); + let mut chain = (&mut ab).chain(&mut cd); + let a = chain.copy_to_bytes(1); + let bc = chain.copy_to_bytes(2); + let d = chain.copy_to_bytes(1); + + assert_eq!(Bytes::copy_from_slice(b"a"), a); + assert_eq!(Bytes::copy_from_slice(b"bc"), bc); + assert_eq!(Bytes::copy_from_slice(b"d"), d); + + // assert `get_bytes` did not allocate + assert_eq!(ab_ptr, a.as_ptr()); + // assert `get_bytes` did not allocate + assert_eq!(cd_ptr.wrapping_offset(1), d.as_ptr()); +} diff --git a/tests/test_take.rs b/tests/test_take.rs index a23a29e..51df91d 100644 --- a/tests/test_take.rs +++ b/tests/test_take.rs @@ -1,6 +1,7 @@ #![warn(rust_2018_idioms)] use bytes::buf::Buf; +use bytes::Bytes; #[test] fn long_take() { @@ -10,3 +11,22 @@ fn long_take() { assert_eq!(11, buf.remaining()); assert_eq!(b"hello world", buf.chunk()); } + +#[test] +fn take_copy_to_bytes() { + let mut abcd = Bytes::copy_from_slice(b"abcd"); + let abcd_ptr = abcd.as_ptr(); + let mut take = (&mut abcd).take(2); + let a = take.copy_to_bytes(1); + assert_eq!(Bytes::copy_from_slice(b"a"), a); + // assert `to_bytes` did not allocate + assert_eq!(abcd_ptr, a.as_ptr()); + assert_eq!(Bytes::copy_from_slice(b"bcd"), abcd); +} + +#[test] +#[should_panic] +fn take_copy_to_bytes_panics() { + let abcd = Bytes::copy_from_slice(b"abcd"); + abcd.take(2).copy_to_bytes(3); +} -- cgit v1.2.3