diff options
author | Haibo Huang <hhb@google.com> | 2021-01-26 20:26:46 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-01-26 20:26:46 +0000 |
commit | 002e162b898f5e57fe5ec8d61457c3bfb8e07864 (patch) | |
tree | 9fee875946571b5e3156284b964bf3617ced0ca1 | |
parent | f5494561bf7fbe436f308f71c80ffd669705edd2 (diff) | |
parent | 3f4f1859116e5384ec7c3a13032df3f09cd294e9 (diff) | |
download | bytes-002e162b898f5e57fe5ec8d61457c3bfb8e07864.tar.gz |
Upgrade rust/crates/bytes to 1.0.1 am: 49f37ac424 am: cf355aa8a9 am: 3f4f185911
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/bytes/+/1546480
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: Ia91cb5eb0dd4ac50f5f625bbfb326726b7b50646
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 22 | ||||
-rw-r--r-- | CHANGELOG.md | 33 | ||||
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | Cargo.toml.orig | 8 | ||||
-rw-r--r-- | METADATA | 10 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | benches/buf.rs | 7 | ||||
-rwxr-xr-x | ci/miri.sh | 11 | ||||
-rw-r--r-- | src/buf/buf_impl.rs | 184 | ||||
-rw-r--r-- | src/buf/buf_mut.rs | 255 | ||||
-rw-r--r-- | src/buf/chain.rs (renamed from src/buf/ext/chain.rs) | 53 | ||||
-rw-r--r-- | src/buf/ext/mod.rs | 186 | ||||
-rw-r--r-- | src/buf/iter.rs | 7 | ||||
-rw-r--r-- | src/buf/limit.rs (renamed from src/buf/ext/limit.rs) | 9 | ||||
-rw-r--r-- | src/buf/mod.rs | 19 | ||||
-rw-r--r-- | src/buf/reader.rs (renamed from src/buf/ext/reader.rs) | 6 | ||||
-rw-r--r-- | src/buf/take.rs (renamed from src/buf/ext/take.rs) | 14 | ||||
-rw-r--r-- | src/buf/uninit_slice.rs | 176 | ||||
-rw-r--r-- | src/buf/vec_deque.rs | 2 | ||||
-rw-r--r-- | src/buf/writer.rs (renamed from src/buf/ext/writer.rs) | 6 | ||||
-rw-r--r-- | src/bytes.rs | 106 | ||||
-rw-r--r-- | src/bytes_mut.rs | 24 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | tests/test_buf.rs | 33 | ||||
-rw-r--r-- | tests/test_buf_mut.rs | 55 | ||||
-rw-r--r-- | tests/test_bytes.rs | 17 | ||||
-rw-r--r-- | tests/test_bytes_odd_alloc.rs | 2 | ||||
-rw-r--r-- | tests/test_chain.rs | 11 | ||||
-rw-r--r-- | tests/test_reader.rs | 6 | ||||
-rw-r--r-- | tests/test_take.rs | 4 |
31 files changed, 709 insertions, 571 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index dd25c50..8a97d76 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "6fdb7391ce83dc71ccaeda6a54211ce723e5d9a5" + "sha1": "7b18c1c076adf9dff4dca28ffc1bbd8759860798" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b99832..fc03588 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ on: env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 + nightly: nightly-2020-12-17 defaults: run: @@ -74,14 +75,11 @@ jobs: # Nightly nightly: name: nightly - env: - # Pin nightly to avoid being impacted by breakage - RUST_VERSION: nightly-2019-09-25 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update $RUST_VERSION && rustup default $RUST_VERSION + run: rustup update $nightly && rustup default $nightly - name: Test run: . ci/test-stable.sh test @@ -120,23 +118,27 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update $nightly && rustup default $nightly - name: Install rust-src run: rustup component add rust-src - name: ASAN / TSAN run: . ci/tsan.sh + miri: + name: miri + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Miri + run: ci/miri.sh # Loom loom: name: loom - env: - # Pin nightly to avoid being impacted by breakage - RUST_VERSION: nightly-2020-05-19 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update $RUST_VERSION && rustup default $RUST_VERSION + run: rustup update $nightly && rustup default $nightly - name: Loom tests run: RUSTFLAGS="--cfg loom -Dwarnings" cargo test --lib @@ -149,6 +151,8 @@ jobs: - nightly - minrust - cross + - tsan + - loom runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b821da..a53a165 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +# 1.0.1 (January 11, 2021) + +### Changed +- mark `Vec::put_slice` with `#[inline]` (#459) + +### Fixed +- Fix deprecation warning (#457) +- use `Box::into_raw` instead of `mem::forget`-in-disguise (#458) + +# 1.0.0 (December 22, 2020) + +### Changed +- Rename Buf/BufMut, methods to chunk/chunk_mut (#450) + +### Removed +- remove unused Buf implementation. (#449) + +# 0.6.0 (October 21, 2020) + +API polish in preparation for a 1.0 release. + +### Changed +- `BufMut` is now an `unsafe` trait (#432). +- `BufMut::bytes_mut()` returns `&mut UninitSlice`, a type owned by `bytes` to + avoid undefined behavior (#433). +- `Buf::copy_to_bytes(len)` replaces `Buf::into_bytes()` (#439). +- `Buf`/`BufMut` utility methods are moved onto the trait and `*Ext` traits are + removed (#431). + +### Removed +- `BufMut::bytes_vectored_mut()` (#430). +- `new` methods on combinator types (#434). + # 0.5.6 (July 13, 2020) - Improve `BytesMut` to reuse buffer when fully `advance`d. @@ -13,10 +13,10 @@ [package] edition = "2018" name = "bytes" -version = "0.5.6" +version = "1.0.1" authors = ["Carl Lerche <me@carllerche.com>", "Sean McArthur <sean@seanmonstar.com>"] description = "Types and traits for working with bytes" -documentation = "https://docs.rs/bytes" +documentation = "https://docs.rs/bytes/1.0.1/bytes/" readme = "README.md" keywords = ["buffers", "zero-copy", "io"] categories = ["network-programming", "data-structures"] @@ -34,4 +34,4 @@ version = "1.0" default = ["std"] std = [] [target."cfg(loom)".dev-dependencies.loom] -version = "0.3" +version = "0.4" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index bcb8f17..8f4e224 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -5,15 +5,15 @@ name = "bytes" # - Update html_root_url. # - Update CHANGELOG.md. # - Update doc URL. -# - Create "v0.5.x" git tag. -version = "0.5.6" +# - Create "v1.0.x" git tag. +version = "1.0.1" license = "MIT" authors = [ "Carl Lerche <me@carllerche.com>", "Sean McArthur <sean@seanmonstar.com>", ] description = "Types and traits for working with bytes" -documentation = "https://docs.rs/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 +31,4 @@ serde = { version = "1.0.60", optional = true, default-features = false, feature serde_test = "1.0" [target.'cfg(loom)'.dev-dependencies] -loom = "0.3" +loom = "0.4" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/bytes/bytes-0.5.6.crate" + value: "https://static.crates.io/crates/bytes/bytes-1.0.1.crate" } - version: "0.5.6" + version: "1.0.1" license_type: NOTICE last_upgrade_date { - year: 2020 - month: 7 - day: 17 + year: 2021 + month: 1 + day: 11 } } @@ -18,7 +18,7 @@ To use `bytes`, first add this to your `Cargo.toml`: ```toml [dependencies] -bytes = "0.5" +bytes = "1" ``` Next, add this to your crate: @@ -33,7 +33,7 @@ Serde support is optional and disabled by default. To enable use the feature `se ```toml [dependencies] -bytes = { version = "0.5", features = ["serde"] } +bytes = { version = "1", features = ["serde"] } ``` ## License diff --git a/benches/buf.rs b/benches/buf.rs index 77b0633..6dc8516 100644 --- a/benches/buf.rs +++ b/benches/buf.rs @@ -53,7 +53,7 @@ impl Buf for TestBuf { assert!(self.pos <= self.buf.len()); self.next_readlen(); } - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { if self.readlen == 0 { Default::default() } else { @@ -87,8 +87,8 @@ impl Buf for TestBufC { self.inner.advance(cnt) } #[inline(never)] - fn bytes(&self) -> &[u8] { - self.inner.bytes() + fn chunk(&self) -> &[u8] { + self.inner.chunk() } } @@ -159,7 +159,6 @@ macro_rules! bench_group { mod get_u8 { use super::*; bench_group!(get_u8); - bench!(option, option); } mod get_u16 { use super::*; diff --git a/ci/miri.sh b/ci/miri.sh new file mode 100755 index 0000000..88d2b6a --- /dev/null +++ b/ci/miri.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) +echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" +rustup set profile minimal +rustup default "$MIRI_NIGHTLY" +rustup component add miri + +cargo miri test +cargo miri test --target mips64-unknown-linux-gnuabi64 diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs index 5cd7c68..16ad8a7 100644 --- a/src/buf/buf_impl.rs +++ b/src/buf/buf_impl.rs @@ -1,3 +1,7 @@ +#[cfg(feature = "std")] +use crate::buf::{reader, Reader}; +use crate::buf::{take, Chain, Take}; + use core::{cmp, mem, ptr}; #[cfg(feature = "std")] @@ -12,7 +16,7 @@ macro_rules! buf_get_impl { // this Option<ret> trick is to avoid keeping a borrow on self // when advance() is called (mut borrow) and to call bytes() only once let ret = $this - .bytes() + .chunk() .get(..SIZE) .map(|src| unsafe { $typ::$conv(*(src as *const _ as *const [_; SIZE])) }); @@ -74,7 +78,7 @@ pub trait Buf { /// the buffer. /// /// This value is greater than or equal to the length of the slice returned - /// by `bytes`. + /// by `chunk()`. /// /// # Examples /// @@ -111,31 +115,31 @@ pub trait Buf { /// /// let mut buf = &b"hello world"[..]; /// - /// assert_eq!(buf.bytes(), &b"hello world"[..]); + /// assert_eq!(buf.chunk(), &b"hello world"[..]); /// /// buf.advance(6); /// - /// assert_eq!(buf.bytes(), &b"world"[..]); + /// assert_eq!(buf.chunk(), &b"world"[..]); /// ``` /// /// # Implementer notes /// /// This function should never panic. Once the end of the buffer is reached, - /// i.e., `Buf::remaining` returns 0, calls to `bytes` should return an + /// i.e., `Buf::remaining` returns 0, calls to `chunk()` should return an /// empty slice. - fn bytes(&self) -> &[u8]; + fn chunk(&self) -> &[u8]; /// Fills `dst` with potentially multiple slices starting at `self`'s /// current position. /// - /// If the `Buf` is backed by disjoint slices of bytes, `bytes_vectored` enables + /// If the `Buf` is backed by disjoint slices of bytes, `chunk_vectored` enables /// fetching more than one slice at once. `dst` is a slice of `IoSlice` /// references, enabling the slice to be directly used with [`writev`] /// without any further conversion. The sum of the lengths of all the /// buffers in `dst` will be less than or equal to `Buf::remaining()`. /// /// The entries in `dst` will be overwritten, but the data **contained** by - /// the slices **will not** be modified. If `bytes_vectored` does not fill every + /// the slices **will not** be modified. If `chunk_vectored` does not fill every /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices /// in `self. /// @@ -145,7 +149,7 @@ pub trait Buf { /// # Implementer notes /// /// This function should never panic. Once the end of the buffer is reached, - /// i.e., `Buf::remaining` returns 0, calls to `bytes_vectored` must return 0 + /// i.e., `Buf::remaining` returns 0, calls to `chunk_vectored` must return 0 /// without mutating `dst`. /// /// Implementations should also take care to properly handle being called @@ -153,13 +157,13 @@ pub trait Buf { /// /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html #[cfg(feature = "std")] - fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { + fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { if dst.is_empty() { return 0; } if self.has_remaining() { - dst[0] = IoSlice::new(self.bytes()); + dst[0] = IoSlice::new(self.chunk()); 1 } else { 0 @@ -168,7 +172,7 @@ pub trait Buf { /// Advance the internal cursor of the Buf /// - /// The next call to `bytes` will return a slice starting `cnt` bytes + /// The next call to `chunk()` will return a slice starting `cnt` bytes /// further into the underlying buffer. /// /// # Examples @@ -178,11 +182,11 @@ pub trait Buf { /// /// let mut buf = &b"hello world"[..]; /// - /// assert_eq!(buf.bytes(), &b"hello world"[..]); + /// assert_eq!(buf.chunk(), &b"hello world"[..]); /// /// buf.advance(6); /// - /// assert_eq!(buf.bytes(), &b"world"[..]); + /// assert_eq!(buf.chunk(), &b"world"[..]); /// ``` /// /// # Panics @@ -249,7 +253,7 @@ pub trait Buf { let cnt; unsafe { - let src = self.bytes(); + let src = self.chunk(); cnt = cmp::min(src.len(), dst.len() - off); ptr::copy_nonoverlapping(src.as_ptr(), dst[off..].as_mut_ptr(), cnt); @@ -279,7 +283,7 @@ pub trait Buf { /// This function panics if there is no more remaining data in `self`. fn get_u8(&mut self) -> u8 { assert!(self.remaining() >= 1); - let ret = self.bytes()[0]; + let ret = self.chunk()[0]; self.advance(1); ret } @@ -302,7 +306,7 @@ pub trait Buf { /// This function panics if there is no more remaining data in `self`. fn get_i8(&mut self) -> i8 { assert!(self.remaining() >= 1); - let ret = self.bytes()[0] as i8; + let ret = self.chunk()[0] as i8; self.advance(1); ret } @@ -791,22 +795,111 @@ pub trait Buf { f64::from_bits(Self::get_u64_le(self)) } - /// Consumes remaining bytes inside self and returns new instance of `Bytes` + /// Consumes `len` bytes inside self and returns new instance of `Bytes` + /// with this data. + /// + /// This function may be optimized by the underlying type to avoid actual + /// copies. For example, `Bytes` implementation will do a shallow copy + /// (ref-count increment). /// /// # Examples /// /// ``` /// use bytes::Buf; /// - /// let bytes = (&b"hello world"[..]).to_bytes(); - /// assert_eq!(&bytes[..], &b"hello world"[..]); + /// let bytes = (&b"hello world"[..]).copy_to_bytes(5); + /// assert_eq!(&bytes[..], &b"hello"[..]); /// ``` - fn to_bytes(&mut self) -> crate::Bytes { + fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes { use super::BufMut; - let mut ret = crate::BytesMut::with_capacity(self.remaining()); - ret.put(self); + + assert!(len <= self.remaining(), "`len` greater than remaining"); + + let mut ret = crate::BytesMut::with_capacity(len); + ret.put(self.take(len)); ret.freeze() } + + /// Creates an adaptor which will read at most `limit` bytes from `self`. + /// + /// This function returns a new instance of `Buf` which will read at most + /// `limit` bytes. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BufMut}; + /// + /// let mut buf = b"hello world"[..].take(5); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(dst, b"hello"); + /// + /// let mut buf = buf.into_inner(); + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(dst, b" world"); + /// ``` + fn take(self, limit: usize) -> Take<Self> + where + Self: Sized, + { + take::new(self, limit) + } + + /// Creates an adaptor which will chain this buffer with another. + /// + /// The returned `Buf` instance will first consume all bytes from `self`. + /// Afterwards the output is equivalent to the output of next. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut chain = b"hello "[..].chain(&b"world"[..]); + /// + /// let full = chain.copy_to_bytes(11); + /// assert_eq!(full.chunk(), b"hello world"); + /// ``` + fn chain<U: Buf>(self, next: U) -> Chain<Self, U> + where + Self: Sized, + { + Chain::new(self, next) + } + + /// Creates an adaptor which implements the `Read` trait for `self`. + /// + /// This function returns a new value which implements `Read` by adapting + /// the `Read` trait functions to the `Buf` trait functions. Given that + /// `Buf` operations are infallible, none of the `Read` functions will + /// return with `Err`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf}; + /// use std::io::Read; + /// + /// let buf = Bytes::from("hello world"); + /// + /// let mut reader = buf.reader(); + /// let mut dst = [0; 1024]; + /// + /// let num = reader.read(&mut dst).unwrap(); + /// + /// assert_eq!(11, num); + /// assert_eq!(&dst[..11], &b"hello world"[..]); + /// ``` + #[cfg(feature = "std")] + fn reader(self) -> Reader<Self> + where + Self: Sized, + { + reader::new(self) + } } macro_rules! deref_forward_buf { @@ -815,13 +908,13 @@ macro_rules! deref_forward_buf { (**self).remaining() } - fn bytes(&self) -> &[u8] { - (**self).bytes() + fn chunk(&self) -> &[u8] { + (**self).chunk() } #[cfg(feature = "std")] - fn bytes_vectored<'b>(&'b self, dst: &mut [IoSlice<'b>]) -> usize { - (**self).bytes_vectored(dst) + fn chunks_vectored<'b>(&'b self, dst: &mut [IoSlice<'b>]) -> usize { + (**self).chunks_vectored(dst) } fn advance(&mut self, cnt: usize) { @@ -908,8 +1001,8 @@ macro_rules! deref_forward_buf { (**self).get_int_le(nbytes) } - fn to_bytes(&mut self) -> crate::Bytes { - (**self).to_bytes() + fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes { + (**self).copy_to_bytes(len) } }; } @@ -929,7 +1022,7 @@ impl Buf for &[u8] { } #[inline] - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { self } @@ -939,35 +1032,6 @@ impl Buf for &[u8] { } } -impl Buf for Option<[u8; 1]> { - fn remaining(&self) -> usize { - if self.is_some() { - 1 - } else { - 0 - } - } - - fn bytes(&self) -> &[u8] { - self.as_ref() - .map(AsRef::as_ref) - .unwrap_or(Default::default()) - } - - fn advance(&mut self, cnt: usize) { - if cnt == 0 { - return; - } - - if self.is_none() { - panic!("overflow"); - } else { - assert_eq!(1, cnt); - *self = None; - } - } -} - #[cfg(feature = "std")] impl<T: AsRef<[u8]>> Buf for std::io::Cursor<T> { fn remaining(&self) -> usize { @@ -981,7 +1045,7 @@ impl<T: AsRef<[u8]>> Buf for std::io::Cursor<T> { len - pos as usize } - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { let len = self.get_ref().as_ref().len(); let pos = self.position(); diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 628b240..f736727 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -1,11 +1,8 @@ -use core::{ - cmp, - mem::{self, MaybeUninit}, - ptr, usize, -}; - +use crate::buf::{limit, Chain, Limit, UninitSlice}; #[cfg(feature = "std")] -use std::fmt; +use crate::buf::{writer, Writer}; + +use core::{cmp, mem, ptr, usize}; use alloc::{boxed::Box, vec::Vec}; @@ -29,12 +26,12 @@ use alloc::{boxed::Box, vec::Vec}; /// /// assert_eq!(buf, b"hello world"); /// ``` -pub trait BufMut { +pub unsafe trait BufMut { /// Returns the number of bytes that can be written from the current /// position until the end of the buffer is reached. /// /// This value is greater than or equal to the length of the slice returned - /// by `bytes_mut`. + /// by `chunk_mut()`. /// /// # Examples /// @@ -59,7 +56,7 @@ pub trait BufMut { /// Advance the internal cursor of the BufMut /// - /// The next call to `bytes_mut` will return a slice starting `cnt` bytes + /// The next call to `chunk_mut` will return a slice starting `cnt` bytes /// further into the underlying buffer. /// /// This function is unsafe because there is no guarantee that the bytes @@ -72,19 +69,14 @@ pub trait BufMut { /// /// let mut buf = Vec::with_capacity(16); /// - /// unsafe { - /// // MaybeUninit::as_mut_ptr - /// buf.bytes_mut()[0].as_mut_ptr().write(b'h'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'e'); - /// - /// buf.advance_mut(2); + /// // Write some data + /// buf.chunk_mut()[0..2].copy_from_slice(b"he"); + /// unsafe { buf.advance_mut(2) }; /// - /// buf.bytes_mut()[0].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[2].as_mut_ptr().write(b'o'); + /// // write more bytes + /// buf.chunk_mut()[0..3].copy_from_slice(b"llo"); /// - /// buf.advance_mut(3); - /// } + /// unsafe { buf.advance_mut(3); } /// /// assert_eq!(5, buf.len()); /// assert_eq!(buf, b"hello"); @@ -143,14 +135,14 @@ pub trait BufMut { /// /// unsafe { /// // MaybeUninit::as_mut_ptr - /// buf.bytes_mut()[0].as_mut_ptr().write(b'h'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'e'); + /// buf.chunk_mut()[0..].as_mut_ptr().write(b'h'); + /// buf.chunk_mut()[1..].as_mut_ptr().write(b'e'); /// /// buf.advance_mut(2); /// - /// buf.bytes_mut()[0].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[2].as_mut_ptr().write(b'o'); + /// buf.chunk_mut()[0..].as_mut_ptr().write(b'l'); + /// buf.chunk_mut()[1..].as_mut_ptr().write(b'l'); + /// buf.chunk_mut()[2..].as_mut_ptr().write(b'o'); /// /// buf.advance_mut(3); /// } @@ -161,54 +153,12 @@ pub trait BufMut { /// /// # Implementer notes /// - /// This function should never panic. `bytes_mut` should return an empty - /// slice **if and only if** `remaining_mut` returns 0. In other words, - /// `bytes_mut` returning an empty slice implies that `remaining_mut` will - /// return 0 and `remaining_mut` returning 0 implies that `bytes_mut` will + /// This function should never panic. `chunk_mut` should return an empty + /// slice **if and only if** `remaining_mut()` returns 0. In other words, + /// `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. - fn bytes_mut(&mut self) -> &mut [MaybeUninit<u8>]; - - /// Fills `dst` with potentially multiple mutable slices starting at `self`'s - /// current position. - /// - /// If the `BufMut` is backed by disjoint slices of bytes, `bytes_vectored_mut` - /// enables fetching more than one slice at once. `dst` is a slice of - /// mutable `IoSliceMut` references, enabling the slice to be directly used with - /// [`readv`] without any further conversion. The sum of the lengths of all - /// the buffers in `dst` will be less than or equal to - /// `Buf::remaining_mut()`. - /// - /// The entries in `dst` will be overwritten, but the data **contained** by - /// the slices **will not** be modified. If `bytes_vectored_mut` does not fill every - /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices - /// in `self. - /// - /// This is a lower level function. Most operations are done with other - /// functions. - /// - /// # Implementer notes - /// - /// This function should never panic. Once the end of the buffer is reached, - /// i.e., `BufMut::remaining_mut` returns 0, calls to `bytes_vectored_mut` must - /// return 0 without mutating `dst`. - /// - /// Implementations should also take care to properly handle being called - /// with `dst` being a zero length slice. - /// - /// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html - #[cfg(feature = "std")] - fn bytes_vectored_mut<'a>(&'a mut self, dst: &mut [IoSliceMut<'a>]) -> usize { - if dst.is_empty() { - return 0; - } - - if self.has_remaining_mut() { - dst[0] = IoSliceMut::from(self.bytes_mut()); - 1 - } else { - 0 - } - } + fn chunk_mut(&mut self) -> &mut UninitSlice; /// Transfer bytes into `self` from `src` and advance the cursor by the /// number of bytes written. @@ -240,8 +190,8 @@ pub trait BufMut { let l; unsafe { - let s = src.bytes(); - let d = self.bytes_mut(); + let s = src.chunk(); + let d = self.chunk_mut(); l = cmp::min(s.len(), d.len()); ptr::copy_nonoverlapping(s.as_ptr(), d.as_mut_ptr() as *mut u8, l); @@ -287,7 +237,7 @@ pub trait BufMut { let cnt; unsafe { - let dst = self.bytes_mut(); + let dst = self.chunk_mut(); cnt = cmp::min(dst.len(), src.len() - off); ptr::copy_nonoverlapping(src[off..].as_ptr(), dst.as_mut_ptr() as *mut u8, cnt); @@ -878,6 +828,83 @@ pub trait BufMut { fn put_f64_le(&mut self, n: f64) { self.put_u64_le(n.to_bits()); } + + /// Creates an adaptor which can write at most `limit` bytes to `self`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let arr = &mut [0u8; 128][..]; + /// assert_eq!(arr.remaining_mut(), 128); + /// + /// let dst = arr.limit(10); + /// assert_eq!(dst.remaining_mut(), 10); + /// ``` + fn limit(self, limit: usize) -> Limit<Self> + where + Self: Sized, + { + limit::new(self, limit) + } + + /// Creates an adaptor which implements the `Write` trait for `self`. + /// + /// This function returns a new value which implements `Write` by adapting + /// the `Write` trait functions to the `BufMut` trait functions. Given that + /// `BufMut` operations are infallible, none of the `Write` functions will + /// return with `Err`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// use std::io::Write; + /// + /// let mut buf = vec![].writer(); + /// + /// let num = buf.write(&b"hello world"[..]).unwrap(); + /// assert_eq!(11, num); + /// + /// let buf = buf.into_inner(); + /// + /// assert_eq!(*buf, b"hello world"[..]); + /// ``` + #[cfg(feature = "std")] + fn writer(self) -> Writer<Self> + where + Self: Sized, + { + writer::new(self) + } + + /// Creates an adapter which will chain this buffer with another. + /// + /// The returned `BufMut` instance will first write to all bytes from + /// `self`. Afterwards, it will write to `next`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut a = [0u8; 5]; + /// let mut b = [0u8; 6]; + /// + /// let mut chain = (&mut a[..]).chain_mut(&mut b[..]); + /// + /// chain.put_slice(b"hello world"); + /// + /// assert_eq!(&a[..], b"hello"); + /// assert_eq!(&b[..], b" world"); + /// ``` + fn chain_mut<U: BufMut>(self, next: U) -> Chain<Self, U> + where + Self: Sized, + { + Chain::new(self, next) + } } macro_rules! deref_forward_bufmut { @@ -886,13 +913,8 @@ macro_rules! deref_forward_bufmut { (**self).remaining_mut() } - fn bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] { - (**self).bytes_mut() - } - - #[cfg(feature = "std")] - fn bytes_vectored_mut<'b>(&'b mut self, dst: &mut [IoSliceMut<'b>]) -> usize { - (**self).bytes_vectored_mut(dst) + fn chunk_mut(&mut self) -> &mut UninitSlice { + (**self).chunk_mut() } unsafe fn advance_mut(&mut self, cnt: usize) { @@ -961,24 +983,24 @@ macro_rules! deref_forward_bufmut { }; } -impl<T: BufMut + ?Sized> BufMut for &mut T { +unsafe impl<T: BufMut + ?Sized> BufMut for &mut T { deref_forward_bufmut!(); } -impl<T: BufMut + ?Sized> BufMut for Box<T> { +unsafe impl<T: BufMut + ?Sized> BufMut for Box<T> { deref_forward_bufmut!(); } -impl BufMut for &mut [u8] { +unsafe impl BufMut for &mut [u8] { #[inline] fn remaining_mut(&self) -> usize { self.len() } #[inline] - fn bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] { - // MaybeUninit is repr(transparent), so safe to transmute - unsafe { mem::transmute(&mut **self) } + fn chunk_mut(&mut self) -> &mut UninitSlice { + // UninitSlice is repr(transparent), so safe to transmute + unsafe { &mut *(*self as *mut [u8] as *mut _) } } #[inline] @@ -989,7 +1011,7 @@ impl BufMut for &mut [u8] { } } -impl BufMut for Vec<u8> { +unsafe impl BufMut for Vec<u8> { #[inline] fn remaining_mut(&self) -> usize { usize::MAX - self.len() @@ -1011,9 +1033,7 @@ impl BufMut for Vec<u8> { } #[inline] - fn bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] { - use core::slice; - + fn chunk_mut(&mut self) -> &mut UninitSlice { if self.capacity() == self.len() { self.reserve(64); // Grow the vec } @@ -1021,13 +1041,12 @@ impl BufMut for Vec<u8> { let cap = self.capacity(); let len = self.len(); - let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>; - unsafe { &mut slice::from_raw_parts_mut(ptr, cap)[len..] } + let ptr = self.as_mut_ptr(); + unsafe { &mut UninitSlice::from_raw_parts_mut(ptr, cap)[len..] } } // Specialize these methods so they can skip checking `remaining_mut` // and `advance_mut`. - fn put<T: super::Buf>(&mut self, mut src: T) where Self: Sized, @@ -1040,7 +1059,7 @@ impl BufMut for Vec<u8> { // a block to contain the src.bytes() borrow { - let s = src.bytes(); + let s = src.chunk(); l = s.len(); self.extend_from_slice(s); } @@ -1049,6 +1068,7 @@ impl BufMut for Vec<u8> { } } + #[inline] fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } @@ -1057,44 +1077,3 @@ impl BufMut for Vec<u8> { // The existence of this function makes the compiler catch if the BufMut // trait is "object-safe" or not. fn _assert_trait_object(_b: &dyn BufMut) {} - -// ===== impl IoSliceMut ===== - -/// A buffer type used for `readv`. -/// -/// This is a wrapper around an `std::io::IoSliceMut`, but does not expose -/// the inner bytes in a safe API, as they may point at uninitialized memory. -/// -/// This is `repr(transparent)` of the `std::io::IoSliceMut`, so it is valid to -/// transmute them. However, as the memory might be uninitialized, care must be -/// taken to not *read* the internal bytes, only *write* to them. -#[repr(transparent)] -#[cfg(feature = "std")] -pub struct IoSliceMut<'a>(std::io::IoSliceMut<'a>); - -#[cfg(feature = "std")] -impl fmt::Debug for IoSliceMut<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("IoSliceMut") - .field("len", &self.0.len()) - .finish() - } -} - -#[cfg(feature = "std")] -impl<'a> From<&'a mut [u8]> for IoSliceMut<'a> { - fn from(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(std::io::IoSliceMut::new(buf)) - } -} - -#[cfg(feature = "std")] -impl<'a> From<&'a mut [MaybeUninit<u8>]> for IoSliceMut<'a> { - fn from(buf: &'a mut [MaybeUninit<u8>]) -> IoSliceMut<'a> { - IoSliceMut(std::io::IoSliceMut::new(unsafe { - // We don't look at the contents, and `std::io::IoSliceMut` - // doesn't either. - mem::transmute::<&'a mut [MaybeUninit<u8>], &'a mut [u8]>(buf) - })) - } -} diff --git a/src/buf/ext/chain.rs b/src/buf/chain.rs index e62e2f1..d68bc2d 100644 --- a/src/buf/ext/chain.rs +++ b/src/buf/chain.rs @@ -1,10 +1,6 @@ -use crate::buf::IntoIter; +use crate::buf::{IntoIter, UninitSlice}; use crate::{Buf, BufMut}; -use core::mem::MaybeUninit; - -#[cfg(feature = "std")] -use crate::buf::IoSliceMut; #[cfg(feature = "std")] use std::io::IoSlice; @@ -20,12 +16,12 @@ use std::io::IoSlice; /// # Examples /// /// ``` -/// use bytes::{Bytes, Buf, buf::BufExt}; +/// use bytes::{Bytes, Buf}; /// /// let mut buf = (&b"hello "[..]) /// .chain(&b"world"[..]); /// -/// let full: Bytes = buf.to_bytes(); +/// let full: Bytes = buf.copy_to_bytes(11); /// assert_eq!(full[..], b"hello world"[..]); /// ``` /// @@ -40,7 +36,7 @@ pub struct Chain<T, U> { impl<T, U> Chain<T, U> { /// Creates a new `Chain` sequencing the provided values. - pub fn new(a: T, b: U) -> Chain<T, U> { + pub(crate) fn new(a: T, b: U) -> Chain<T, U> { Chain { a, b } } @@ -49,7 +45,7 @@ impl<T, U> Chain<T, U> { /// # Examples /// /// ``` - /// use bytes::buf::BufExt; + /// use bytes::Buf; /// /// let buf = (&b"hello"[..]) /// .chain(&b"world"[..]); @@ -65,14 +61,14 @@ impl<T, U> Chain<T, U> { /// # Examples /// /// ``` - /// use bytes::{Buf, buf::BufExt}; + /// use bytes::Buf; /// /// let mut buf = (&b"hello"[..]) /// .chain(&b"world"[..]); /// /// buf.first_mut().advance(1); /// - /// let full = buf.to_bytes(); + /// let full = buf.copy_to_bytes(9); /// assert_eq!(full, b"elloworld"[..]); /// ``` pub fn first_mut(&mut self) -> &mut T { @@ -84,7 +80,7 @@ impl<T, U> Chain<T, U> { /// # Examples /// /// ``` - /// use bytes::buf::BufExt; + /// use bytes::Buf; /// /// let buf = (&b"hello"[..]) /// .chain(&b"world"[..]); @@ -100,14 +96,14 @@ impl<T, U> Chain<T, U> { /// # Examples /// /// ``` - /// use bytes::{Buf, buf::BufExt}; + /// use bytes::Buf; /// /// let mut buf = (&b"hello "[..]) /// .chain(&b"world"[..]); /// /// buf.last_mut().advance(1); /// - /// let full = buf.to_bytes(); + /// let full = buf.copy_to_bytes(10); /// assert_eq!(full, b"hello orld"[..]); /// ``` pub fn last_mut(&mut self) -> &mut U { @@ -119,7 +115,7 @@ impl<T, U> Chain<T, U> { /// # Examples /// /// ``` - /// use bytes::buf::BufExt; + /// use bytes::Buf; /// /// let chain = (&b"hello"[..]) /// .chain(&b"world"[..]); @@ -142,11 +138,11 @@ where self.a.remaining() + self.b.remaining() } - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { if self.a.has_remaining() { - self.a.bytes() + self.a.chunk() } else { - self.b.bytes() + self.b.chunk() } } @@ -169,14 +165,14 @@ where } #[cfg(feature = "std")] - fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { - let mut n = self.a.bytes_vectored(dst); - n += self.b.bytes_vectored(&mut dst[n..]); + fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { + let mut n = self.a.chunks_vectored(dst); + n += self.b.chunks_vectored(&mut dst[n..]); n } } -impl<T, U> BufMut for Chain<T, U> +unsafe impl<T, U> BufMut for Chain<T, U> where T: BufMut, U: BufMut, @@ -185,11 +181,11 @@ where self.a.remaining_mut() + self.b.remaining_mut() } - fn bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] { + fn chunk_mut(&mut self) -> &mut UninitSlice { if self.a.has_remaining_mut() { - self.a.bytes_mut() + self.a.chunk_mut() } else { - self.b.bytes_mut() + self.b.chunk_mut() } } @@ -210,13 +206,6 @@ where self.b.advance_mut(cnt); } - - #[cfg(feature = "std")] - fn bytes_vectored_mut<'a>(&'a mut self, dst: &mut [IoSliceMut<'a>]) -> usize { - let mut n = self.a.bytes_vectored_mut(dst); - n += self.b.bytes_vectored_mut(&mut dst[n..]); - n - } } impl<T, U> IntoIterator for Chain<T, U> diff --git a/src/buf/ext/mod.rs b/src/buf/ext/mod.rs deleted file mode 100644 index 4a29267..0000000 --- a/src/buf/ext/mod.rs +++ /dev/null @@ -1,186 +0,0 @@ -//! Extra utilities for `Buf` and `BufMut` types. - -use super::{Buf, BufMut}; - -mod chain; -mod limit; -#[cfg(feature = "std")] -mod reader; -mod take; -#[cfg(feature = "std")] -mod writer; - -pub use self::chain::Chain; -pub use self::limit::Limit; -pub use self::take::Take; - -#[cfg(feature = "std")] -pub use self::{reader::Reader, writer::Writer}; - -/// Extra methods for implementations of `Buf`. -pub trait BufExt: Buf { - /// Creates an adaptor which will read at most `limit` bytes from `self`. - /// - /// This function returns a new instance of `Buf` which will read at most - /// `limit` bytes. - /// - /// # Examples - /// - /// ``` - /// use bytes::{BufMut, buf::BufExt}; - /// - /// let mut buf = b"hello world"[..].take(5); - /// let mut dst = vec![]; - /// - /// dst.put(&mut buf); - /// assert_eq!(dst, b"hello"); - /// - /// let mut buf = buf.into_inner(); - /// dst.clear(); - /// dst.put(&mut buf); - /// assert_eq!(dst, b" world"); - /// ``` - fn take(self, limit: usize) -> Take<Self> - where - Self: Sized, - { - take::new(self, limit) - } - - /// Creates an adaptor which will chain this buffer with another. - /// - /// The returned `Buf` instance will first consume all bytes from `self`. - /// Afterwards the output is equivalent to the output of next. - /// - /// # Examples - /// - /// ``` - /// use bytes::{Buf, buf::BufExt}; - /// - /// let mut chain = b"hello "[..].chain(&b"world"[..]); - /// - /// let full = chain.to_bytes(); - /// assert_eq!(full.bytes(), b"hello world"); - /// ``` - fn chain<U: Buf>(self, next: U) -> Chain<Self, U> - where - Self: Sized, - { - Chain::new(self, next) - } - - /// Creates an adaptor which implements the `Read` trait for `self`. - /// - /// This function returns a new value which implements `Read` by adapting - /// the `Read` trait functions to the `Buf` trait functions. Given that - /// `Buf` operations are infallible, none of the `Read` functions will - /// return with `Err`. - /// - /// # Examples - /// - /// ``` - /// use bytes::{Bytes, buf::BufExt}; - /// use std::io::Read; - /// - /// let buf = Bytes::from("hello world"); - /// - /// let mut reader = buf.reader(); - /// let mut dst = [0; 1024]; - /// - /// let num = reader.read(&mut dst).unwrap(); - /// - /// assert_eq!(11, num); - /// assert_eq!(&dst[..11], &b"hello world"[..]); - /// ``` - #[cfg(feature = "std")] - fn reader(self) -> Reader<Self> - where - Self: Sized, - { - reader::new(self) - } -} - -impl<B: Buf + ?Sized> BufExt for B {} - -/// Extra methods for implementations of `BufMut`. -pub trait BufMutExt: BufMut { - /// Creates an adaptor which can write at most `limit` bytes to `self`. - /// - /// # Examples - /// - /// ``` - /// use bytes::{BufMut, buf::BufMutExt}; - /// - /// let arr = &mut [0u8; 128][..]; - /// assert_eq!(arr.remaining_mut(), 128); - /// - /// let dst = arr.limit(10); - /// assert_eq!(dst.remaining_mut(), 10); - /// ``` - fn limit(self, limit: usize) -> Limit<Self> - where - Self: Sized, - { - limit::new(self, limit) - } - - /// Creates an adaptor which implements the `Write` trait for `self`. - /// - /// This function returns a new value which implements `Write` by adapting - /// the `Write` trait functions to the `BufMut` trait functions. Given that - /// `BufMut` operations are infallible, none of the `Write` functions will - /// return with `Err`. - /// - /// # Examples - /// - /// ``` - /// use bytes::buf::BufMutExt; - /// use std::io::Write; - /// - /// let mut buf = vec![].writer(); - /// - /// let num = buf.write(&b"hello world"[..]).unwrap(); - /// assert_eq!(11, num); - /// - /// let buf = buf.into_inner(); - /// - /// assert_eq!(*buf, b"hello world"[..]); - /// ``` - #[cfg(feature = "std")] - fn writer(self) -> Writer<Self> - where - Self: Sized, - { - writer::new(self) - } - - /// Creates an adapter which will chain this buffer with another. - /// - /// The returned `BufMut` instance will first write to all bytes from - /// `self`. Afterwards, it will write to `next`. - /// - /// # Examples - /// - /// ``` - /// use bytes::{BufMut, buf::BufMutExt}; - /// - /// let mut a = [0u8; 5]; - /// let mut b = [0u8; 6]; - /// - /// let mut chain = (&mut a[..]).chain_mut(&mut b[..]); - /// - /// chain.put_slice(b"hello world"); - /// - /// assert_eq!(&a[..], b"hello"); - /// assert_eq!(&b[..], b" world"); - /// ``` - fn chain_mut<U: BufMut>(self, next: U) -> Chain<Self, U> - where - Self: Sized, - { - Chain::new(self, next) - } -} - -impl<B: BufMut + ?Sized> BufMutExt for B {} diff --git a/src/buf/iter.rs b/src/buf/iter.rs index 0f9bdc0..8914a40 100644 --- a/src/buf/iter.rs +++ b/src/buf/iter.rs @@ -34,17 +34,16 @@ impl<T> IntoIter<T> { /// /// ``` /// use bytes::Bytes; - /// use bytes::buf::IntoIter; /// /// let buf = Bytes::from_static(b"abc"); - /// let mut iter = IntoIter::new(buf); + /// let mut iter = buf.into_iter(); /// /// assert_eq!(iter.next(), Some(b'a')); /// assert_eq!(iter.next(), Some(b'b')); /// assert_eq!(iter.next(), Some(b'c')); /// assert_eq!(iter.next(), None); /// ``` - pub fn new(inner: T) -> IntoIter<T> { + pub(crate) fn new(inner: T) -> IntoIter<T> { IntoIter { inner } } @@ -118,7 +117,7 @@ impl<T: Buf> Iterator for IntoIter<T> { return None; } - let b = self.inner.bytes()[0]; + let b = self.inner.chunk()[0]; self.inner.advance(1); Some(b) diff --git a/src/buf/ext/limit.rs b/src/buf/limit.rs index a36ecee..b422be5 100644 --- a/src/buf/ext/limit.rs +++ b/src/buf/limit.rs @@ -1,6 +1,7 @@ +use crate::buf::UninitSlice; use crate::BufMut; -use core::{cmp, mem::MaybeUninit}; +use core::cmp; /// A `BufMut` adapter which limits the amount of bytes that can be written /// to an underlying buffer. @@ -55,13 +56,13 @@ impl<T> Limit<T> { } } -impl<T: BufMut> BufMut for Limit<T> { +unsafe impl<T: BufMut> BufMut for Limit<T> { fn remaining_mut(&self) -> usize { cmp::min(self.inner.remaining_mut(), self.limit) } - fn bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] { - let bytes = self.inner.bytes_mut(); + fn chunk_mut(&mut self) -> &mut UninitSlice { + let bytes = self.inner.chunk_mut(); let end = cmp::min(bytes.len(), self.limit); &mut bytes[..end] } diff --git a/src/buf/mod.rs b/src/buf/mod.rs index 1d7292c..c4c0a57 100644 --- a/src/buf/mod.rs +++ b/src/buf/mod.rs @@ -18,13 +18,24 @@ mod buf_impl; mod buf_mut; -pub mod ext; +mod chain; mod iter; +mod limit; +#[cfg(feature = "std")] +mod reader; +mod take; +mod uninit_slice; mod vec_deque; +#[cfg(feature = "std")] +mod writer; pub use self::buf_impl::Buf; pub use self::buf_mut::BufMut; -#[cfg(feature = "std")] -pub use self::buf_mut::IoSliceMut; -pub use self::ext::{BufExt, BufMutExt}; +pub use self::chain::Chain; pub use self::iter::IntoIter; +pub use self::limit::Limit; +pub use self::take::Take; +pub use self::uninit_slice::UninitSlice; + +#[cfg(feature = "std")] +pub use self::{reader::Reader, writer::Writer}; diff --git a/src/buf/ext/reader.rs b/src/buf/reader.rs index dde3548..f2b4d98 100644 --- a/src/buf/ext/reader.rs +++ b/src/buf/reader.rs @@ -24,7 +24,7 @@ impl<B: Buf> Reader<B> { /// # Examples /// /// ```rust - /// use bytes::buf::BufExt; + /// use bytes::Buf; /// /// let buf = b"hello world".reader(); /// @@ -46,7 +46,7 @@ impl<B: Buf> Reader<B> { /// # Examples /// /// ```rust - /// use bytes::{Buf, buf::BufExt}; + /// use bytes::Buf; /// use std::io; /// /// let mut buf = b"hello world".reader(); @@ -73,7 +73,7 @@ impl<B: Buf + Sized> io::Read for Reader<B> { impl<B: Buf + Sized> io::BufRead for Reader<B> { fn fill_buf(&mut self) -> io::Result<&[u8]> { - Ok(self.buf.bytes()) + Ok(self.buf.chunk()) } fn consume(&mut self, amt: usize) { self.buf.advance(amt) diff --git a/src/buf/ext/take.rs b/src/buf/take.rs index 1d84868..1747f6e 100644 --- a/src/buf/ext/take.rs +++ b/src/buf/take.rs @@ -22,7 +22,7 @@ impl<T> Take<T> { /// # Examples /// /// ```rust - /// use bytes::buf::{BufMut, BufExt}; + /// use bytes::{Buf, BufMut}; /// /// let mut buf = b"hello world".take(2); /// let mut dst = vec![]; @@ -47,7 +47,7 @@ impl<T> Take<T> { /// # Examples /// /// ```rust - /// use bytes::{Buf, buf::BufExt}; + /// use bytes::Buf; /// /// let buf = b"hello world".take(2); /// @@ -64,7 +64,7 @@ impl<T> Take<T> { /// # Examples /// /// ```rust - /// use bytes::{Buf, BufMut, buf::BufExt}; + /// use bytes::{Buf, BufMut}; /// /// let mut buf = b"hello world".take(2); /// let mut dst = vec![]; @@ -88,7 +88,7 @@ impl<T> Take<T> { /// # Examples /// /// ```rust - /// use bytes::{Buf, buf::BufExt}; + /// use bytes::Buf; /// /// let mut buf = b"hello world".take(2); /// @@ -110,7 +110,7 @@ impl<T> Take<T> { /// # Examples /// /// ```rust - /// use bytes::{BufMut, buf::BufExt}; + /// use bytes::{Buf, BufMut}; /// /// let mut buf = b"hello world".take(2); /// let mut dst = vec![]; @@ -134,8 +134,8 @@ impl<T: Buf> Buf for Take<T> { cmp::min(self.inner.remaining(), self.limit) } - fn bytes(&self) -> &[u8] { - let bytes = self.inner.bytes(); + fn chunk(&self) -> &[u8] { + let bytes = self.inner.chunk(); &bytes[..cmp::min(bytes.len(), self.limit)] } diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs new file mode 100644 index 0000000..73f4e89 --- /dev/null +++ b/src/buf/uninit_slice.rs @@ -0,0 +1,176 @@ +use core::fmt; +use core::mem::MaybeUninit; +use core::ops::{ + Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, +}; + +/// Uninitialized byte slice. +/// +/// Returned by `BufMut::chunk_mut()`, the referenced byte slice may be +/// uninitialized. The wrapper provides safe access without introducing +/// undefined behavior. +/// +/// The safety invariants of this wrapper are: +/// +/// 1. Reading from an `UninitSlice` is undefined behavior. +/// 2. Writing uninitialized bytes to an `UninitSlice` is undefined behavior. +/// +/// The difference between `&mut UninitSlice` and `&mut [MaybeUninit<u8>]` is +/// that it is possible in safe code to write uninitialized bytes to an +/// `&mut [MaybeUninit<u8>]`, which this type prohibits. +#[repr(transparent)] +pub struct UninitSlice([MaybeUninit<u8>]); + +impl UninitSlice { + /// Create a `&mut UninitSlice` from a pointer and a length. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` references a valid memory region owned + /// by the caller representing a byte slice for the duration of `'a`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::UninitSlice; + /// + /// let bytes = b"hello world".to_vec(); + /// let ptr = bytes.as_ptr() as *mut _; + /// let len = bytes.len(); + /// + /// let slice = unsafe { UninitSlice::from_raw_parts_mut(ptr, len) }; + /// ``` + pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { + let maybe_init: &mut [MaybeUninit<u8>] = + core::slice::from_raw_parts_mut(ptr as *mut _, len); + &mut *(maybe_init as *mut [MaybeUninit<u8>] as *mut UninitSlice) + } + + /// Write a single byte at the specified offset. + /// + /// # Panics + /// + /// The function panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::UninitSlice; + /// + /// let mut data = [b'f', b'o', b'o']; + /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + /// + /// slice.write_byte(0, b'b'); + /// + /// assert_eq!(b"boo", &data[..]); + /// ``` + pub fn write_byte(&mut self, index: usize, byte: u8) { + assert!(index < self.len()); + + unsafe { self[index..].as_mut_ptr().write(byte) } + } + + /// Copies bytes from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// # Panics + /// + /// The function panics if `src` has a different length than `self`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::UninitSlice; + /// + /// let mut data = [b'f', b'o', b'o']; + /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + /// + /// slice.copy_from_slice(b"bar"); + /// + /// assert_eq!(b"bar", &data[..]); + /// ``` + pub fn copy_from_slice(&mut self, src: &[u8]) { + use core::ptr; + + assert_eq!(self.len(), src.len()); + + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len()); + } + } + + /// Return a raw pointer to the slice's buffer. + /// + /// # Safety + /// + /// The caller **must not** read from the referenced memory and **must not** + /// write **uninitialized** bytes to the slice either. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut data = [0, 1, 2]; + /// let mut slice = &mut data[..]; + /// let ptr = BufMut::chunk_mut(&mut slice).as_mut_ptr(); + /// ``` + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.0.as_mut_ptr() as *mut _ + } + + /// Returns the number of bytes in the slice. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut data = [0, 1, 2]; + /// let mut slice = &mut data[..]; + /// let len = BufMut::chunk_mut(&mut slice).len(); + /// + /// assert_eq!(len, 3); + /// ``` + pub fn len(&self) -> usize { + self.0.len() + } +} + +impl fmt::Debug for UninitSlice { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("UninitSlice[...]").finish() + } +} + +macro_rules! impl_index { + ($($t:ty),*) => { + $( + impl Index<$t> for UninitSlice { + type Output = UninitSlice; + + fn index(&self, index: $t) -> &UninitSlice { + let maybe_uninit: &[MaybeUninit<u8>] = &self.0[index]; + unsafe { &*(maybe_uninit as *const [MaybeUninit<u8>] as *const UninitSlice) } + } + } + + impl IndexMut<$t> for UninitSlice { + fn index_mut(&mut self, index: $t) -> &mut UninitSlice { + let maybe_uninit: &mut [MaybeUninit<u8>] = &mut self.0[index]; + unsafe { &mut *(maybe_uninit as *mut [MaybeUninit<u8>] as *mut UninitSlice) } + } + } + )* + }; +} + +impl_index!( + Range<usize>, + RangeFrom<usize>, + RangeFull, + RangeInclusive<usize>, + RangeTo<usize>, + RangeToInclusive<usize> +); diff --git a/src/buf/vec_deque.rs b/src/buf/vec_deque.rs index 195e689..263167e 100644 --- a/src/buf/vec_deque.rs +++ b/src/buf/vec_deque.rs @@ -7,7 +7,7 @@ impl Buf for VecDeque<u8> { self.len() } - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { let (s1, s2) = self.as_slices(); if s1.is_empty() { s2 diff --git a/src/buf/ext/writer.rs b/src/buf/writer.rs index a14197c..261d7cd 100644 --- a/src/buf/ext/writer.rs +++ b/src/buf/writer.rs @@ -24,7 +24,7 @@ impl<B: BufMut> Writer<B> { /// # Examples /// /// ```rust - /// use bytes::buf::BufMutExt; + /// use bytes::BufMut; /// /// let buf = Vec::with_capacity(1024).writer(); /// @@ -41,7 +41,7 @@ impl<B: BufMut> Writer<B> { /// # Examples /// /// ```rust - /// use bytes::buf::BufMutExt; + /// use bytes::BufMut; /// /// let mut buf = vec![].writer(); /// @@ -58,7 +58,7 @@ impl<B: BufMut> Writer<B> { /// # Examples /// /// ```rust - /// use bytes::buf::BufMutExt; + /// use bytes::BufMut; /// use std::io; /// /// let mut buf = vec![].writer(); diff --git a/src/bytes.rs b/src/bytes.rs index 79a09f3..b1b35ea 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -10,16 +10,23 @@ use crate::loom::sync::atomic::AtomicMut; use crate::loom::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; use crate::Buf; -/// A reference counted contiguous slice of memory. +/// A cheaply cloneable and sliceable chunk of contiguous memory. /// /// `Bytes` is an efficient container for storing and operating on contiguous /// slices of memory. It is intended for use primarily in networking code, but /// could have applications elsewhere as well. /// /// `Bytes` values facilitate zero-copy network programming by allowing multiple -/// `Bytes` objects to point to the same underlying memory. This is managed by -/// using a reference count to track when the memory is no longer needed and can -/// be freed. +/// `Bytes` objects to point to the same underlying memory. +/// +/// `Bytes` does not have a single implementation. It is an interface, whose +/// exact behavior is implemented through dynamic dispatch in several underlying +/// implementations of `Bytes`. +/// +/// All `Bytes` implementations must fulfill the following requirements: +/// - They are cheaply cloneable and thereby shareable between an unlimited amount +/// of components, for example by modifying a reference count. +/// - Instances can be sliced to refer to a subset of the the original buffer. /// /// ``` /// use bytes::Bytes; @@ -41,17 +48,33 @@ use crate::Buf; /// to track information about which segment of the underlying memory the /// `Bytes` handle has access to. /// -/// `Bytes` keeps both a pointer to the shared `Arc` containing the full memory +/// `Bytes` keeps both a pointer to the shared state containing the full memory /// slice and a pointer to the start of the region visible by the handle. /// `Bytes` also tracks the length of its view into the memory. /// /// # Sharing /// -/// The memory itself is reference counted, and multiple `Bytes` objects may -/// point to the same region. Each `Bytes` handle point to different sections within -/// the memory region, and `Bytes` handle may or may not have overlapping views +/// `Bytes` contains a vtable, which allows implementations of `Bytes` to define +/// how sharing/cloneing is implemented in detail. +/// When `Bytes::clone()` is called, `Bytes` will call the vtable function for +/// cloning the backing storage in order to share it behind between multiple +/// `Bytes` instances. +/// +/// For `Bytes` implementations which refer to constant memory (e.g. created +/// via `Bytes::from_static()`) the cloning implementation will be a no-op. +/// +/// For `Bytes` implementations which point to a reference counted shared storage +/// (e.g. an `Arc<[u8]>`), sharing will be implemented by increasing the +/// the reference count. +/// +/// Due to this mechanism, multiple `Bytes` instances may point to the same +/// shared memory region. +/// Each `Bytes` instance can point to different sections within that +/// memory region, and `Bytes` instances may or may not have overlapping views /// into the memory. /// +/// The following diagram visualizes a scenario where 2 `Bytes` instances make +/// use of an `Arc`-based backing storage, and provide access to different views: /// /// ```text /// @@ -175,7 +198,7 @@ impl Bytes { self.len == 0 } - ///Creates `Bytes` instance from slice, by copying it. + /// Creates `Bytes` instance from slice, by copying it. pub fn copy_from_slice(data: &[u8]) -> Self { data.to_vec().into() } @@ -214,7 +237,7 @@ impl Bytes { }; let end = match range.end_bound() { - Bound::Included(&n) => n + 1, + Bound::Included(&n) => n.checked_add(1).expect("out of range"), Bound::Excluded(&n) => n, Bound::Unbounded => len, }; @@ -507,7 +530,7 @@ impl Buf for Bytes { } #[inline] - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { self.as_slice() } @@ -525,8 +548,14 @@ impl Buf for Bytes { } } - fn to_bytes(&mut self) -> crate::Bytes { - core::mem::replace(self, Bytes::new()) + fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes { + if len == self.remaining() { + core::mem::replace(self, Bytes::new()) + } else { + let ret = self.slice(..len); + self.advance(len); + ret + } } } @@ -777,8 +806,7 @@ impl From<Vec<u8>> for Bytes { let slice = vec.into_boxed_slice(); let len = slice.len(); - let ptr = slice.as_ptr(); - drop(Box::into_raw(slice)); + let ptr = Box::into_raw(slice) as *mut u8; if ptr as usize & 0x1 == 0 { let data = ptr as usize | KIND_VEC; @@ -994,33 +1022,35 @@ unsafe fn shallow_clone_vec( // `Release` is used synchronize with other threads that // will load the `arc` field. // - // If the `compare_and_swap` fails, then the thread lost the + // If the `compare_exchange` fails, then the thread lost the // race to promote the buffer to shared. The `Acquire` - // ordering will synchronize with the `compare_and_swap` + // ordering will synchronize with the `compare_exchange` // that happened in the other thread and the `Shared` // pointed to by `actual` will be visible. - let actual = atom.compare_and_swap(ptr as _, shared as _, Ordering::AcqRel); - - if actual as usize == ptr as usize { - // The upgrade was successful, the new handle can be - // returned. - return Bytes { - ptr: offset, - len, - data: AtomicPtr::new(shared as _), - vtable: &SHARED_VTABLE, - }; + match atom.compare_exchange(ptr as _, shared as _, Ordering::AcqRel, Ordering::Acquire) { + Ok(actual) => { + debug_assert!(actual as usize == ptr as usize); + // The upgrade was successful, the new handle can be + // returned. + Bytes { + ptr: offset, + len, + data: AtomicPtr::new(shared as _), + vtable: &SHARED_VTABLE, + } + } + Err(actual) => { + // The upgrade failed, a concurrent clone happened. Release + // the allocation that was made in this thread, it will not + // be needed. + let shared = Box::from_raw(shared); + mem::forget(*shared); + + // Buffer already promoted to shared storage, so increment ref + // count. + shallow_clone_arc(actual as _, offset, len) + } } - - // The upgrade failed, a concurrent clone happened. Release - // the allocation that was made in this thread, it will not - // be needed. - let shared = Box::from_raw(shared); - mem::forget(*shared); - - // Buffer already promoted to shared storage, so increment ref - // count. - shallow_clone_arc(actual as _, offset, len) } unsafe fn release_shared(ptr: *mut Shared) { diff --git a/src/bytes_mut.rs b/src/bytes_mut.rs index a7a8e57..61c0460 100644 --- a/src/bytes_mut.rs +++ b/src/bytes_mut.rs @@ -11,7 +11,7 @@ use alloc::{ vec::Vec, }; -use crate::buf::IntoIter; +use crate::buf::{IntoIter, UninitSlice}; use crate::bytes::Vtable; #[allow(unused)] use crate::loom::sync::atomic::AtomicMut; @@ -445,7 +445,7 @@ impl BytesMut { let additional = new_len - len; self.reserve(additional); unsafe { - let dst = self.bytes_mut().as_mut_ptr(); + let dst = self.chunk_mut().as_mut_ptr(); ptr::write_bytes(dst, value, additional); self.set_len(new_len); } @@ -684,7 +684,7 @@ impl BytesMut { self.reserve(cnt); unsafe { - let dst = self.maybe_uninit_bytes(); + let dst = self.uninit_slice(); // Reserved above debug_assert!(dst.len() >= cnt); @@ -910,12 +910,12 @@ impl BytesMut { } #[inline] - fn maybe_uninit_bytes(&mut self) -> &mut [mem::MaybeUninit<u8>] { + fn uninit_slice(&mut self) -> &mut UninitSlice { unsafe { let ptr = self.ptr.as_ptr().offset(self.len as isize); let len = self.cap - self.len; - slice::from_raw_parts_mut(ptr as *mut mem::MaybeUninit<u8>, len) + UninitSlice::from_raw_parts_mut(ptr, len) } } } @@ -944,7 +944,7 @@ impl Buf for BytesMut { } #[inline] - fn bytes(&self) -> &[u8] { + fn chunk(&self) -> &[u8] { self.as_slice() } @@ -961,12 +961,12 @@ impl Buf for BytesMut { } } - fn to_bytes(&mut self) -> crate::Bytes { - self.split().freeze() + fn copy_to_bytes(&mut self, len: usize) -> crate::Bytes { + self.split_to(len).freeze() } } -impl BufMut for BytesMut { +unsafe impl BufMut for BytesMut { #[inline] fn remaining_mut(&self) -> usize { usize::MAX - self.len() @@ -985,11 +985,11 @@ impl BufMut for BytesMut { } #[inline] - fn bytes_mut(&mut self) -> &mut [mem::MaybeUninit<u8>] { + fn chunk_mut(&mut self) -> &mut UninitSlice { if self.capacity() == self.len() { self.reserve(64); } - self.maybe_uninit_bytes() + self.uninit_slice() } // Specialize these methods so they can skip checking `remaining_mut` @@ -1000,7 +1000,7 @@ impl BufMut for BytesMut { Self: Sized, { while src.has_remaining() { - let s = src.bytes(); + let s = src.chunk(); let l = s.len(); self.extend_from_slice(s); src.advance(l); @@ -3,7 +3,7 @@ no_crate_inject, attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) ))] -#![doc(html_root_url = "https://docs.rs/bytes/0.5.6")] +#![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.rs b/tests/test_buf.rs index 17bdd54..fbad003 100644 --- a/tests/test_buf.rs +++ b/tests/test_buf.rs @@ -9,17 +9,17 @@ fn test_fresh_cursor_vec() { let mut buf = &b"hello"[..]; assert_eq!(buf.remaining(), 5); - assert_eq!(buf.bytes(), b"hello"); + assert_eq!(buf.chunk(), b"hello"); buf.advance(2); assert_eq!(buf.remaining(), 3); - assert_eq!(buf.bytes(), b"llo"); + assert_eq!(buf.chunk(), b"llo"); buf.advance(3); assert_eq!(buf.remaining(), 0); - assert_eq!(buf.bytes(), b""); + assert_eq!(buf.chunk(), b""); } #[test] @@ -53,7 +53,7 @@ fn test_bufs_vec() { let mut dst = [IoSlice::new(b1), IoSlice::new(b2)]; - assert_eq!(1, buf.bytes_vectored(&mut dst[..])); + assert_eq!(1, buf.chunks_vectored(&mut dst[..])); } #[test] @@ -63,9 +63,9 @@ fn test_vec_deque() { let mut buffer: VecDeque<u8> = VecDeque::new(); buffer.extend(b"hello world"); assert_eq!(11, buffer.remaining()); - assert_eq!(b"hello world", buffer.bytes()); + assert_eq!(b"hello world", buffer.chunk()); buffer.advance(6); - assert_eq!(b"world", buffer.bytes()); + assert_eq!(b"world", buffer.chunk()); buffer.extend(b" piece"); let mut out = [0; 11]; buffer.copy_to_slice(&mut out); @@ -81,8 +81,8 @@ fn test_deref_buf_forwards() { unreachable!("remaining"); } - fn bytes(&self) -> &[u8] { - unreachable!("bytes"); + fn chunk(&self) -> &[u8] { + unreachable!("chunk"); } fn advance(&mut self, _: usize) { @@ -101,3 +101,20 @@ fn test_deref_buf_forwards() { assert_eq!((Box::new(Special) as Box<dyn Buf>).get_u8(), b'x'); assert_eq!(Box::new(Special).get_u8(), b'x'); } + +#[test] +fn copy_to_bytes_less() { + let mut buf = &b"hello world"[..]; + + let bytes = buf.copy_to_bytes(5); + assert_eq!(bytes, &b"hello"[..]); + assert_eq!(buf, &b" world"[..]) +} + +#[test] +#[should_panic] +fn copy_to_bytes_overflow() { + let mut buf = &b"hello world"[..]; + + let _bytes = buf.copy_to_bytes(12); +} diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index b91e2e5..8d270e3 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -1,7 +1,6 @@ #![warn(rust_2018_idioms)] -#[cfg(feature = "std")] -use bytes::buf::IoSliceMut; +use bytes::buf::UninitSlice; use bytes::{BufMut, BytesMut}; use core::fmt::Write; use core::usize; @@ -12,7 +11,7 @@ fn test_vec_as_mut_buf() { assert_eq!(buf.remaining_mut(), usize::MAX); - assert!(buf.bytes_mut().len() >= 64); + assert!(buf.chunk_mut().len() >= 64); buf.put(&b"zomg"[..]); @@ -66,23 +65,6 @@ fn test_clone() { assert!(buf != buf2); } -#[cfg(feature = "std")] -#[test] -fn test_bufs_vec_mut() { - let b1: &mut [u8] = &mut []; - let b2: &mut [u8] = &mut []; - let mut dst = [IoSliceMut::from(b1), IoSliceMut::from(b2)]; - - // with no capacity - let mut buf = BytesMut::new(); - assert_eq!(buf.capacity(), 0); - assert_eq!(1, buf.bytes_vectored_mut(&mut dst[..])); - - // with capacity - let mut buf = BytesMut::with_capacity(64); - assert_eq!(1, buf.bytes_vectored_mut(&mut dst[..])); -} - #[test] fn test_mut_slice() { let mut v = vec![0, 0, 0, 0]; @@ -94,13 +76,13 @@ fn test_mut_slice() { fn test_deref_bufmut_forwards() { struct Special; - impl BufMut for Special { + unsafe impl BufMut for Special { fn remaining_mut(&self) -> usize { unreachable!("remaining_mut"); } - fn bytes_mut(&mut self) -> &mut [std::mem::MaybeUninit<u8>] { - unreachable!("bytes_mut"); + fn chunk_mut(&mut self) -> &mut UninitSlice { + unreachable!("chunk_mut"); } unsafe fn advance_mut(&mut self, _: usize) { @@ -118,3 +100,30 @@ fn test_deref_bufmut_forwards() { (Box::new(Special) as Box<dyn BufMut>).put_u8(b'x'); Box::new(Special).put_u8(b'x'); } + +#[test] +#[should_panic] +fn write_byte_panics_if_out_of_bounds() { + let mut data = [b'b', b'a', b'r']; + + let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + slice.write_byte(4, b'f'); +} + +#[test] +#[should_panic] +fn copy_from_slice_panics_if_different_length_1() { + let mut data = [b'b', b'a', b'r']; + + let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + slice.copy_from_slice(b"a"); +} + +#[test] +#[should_panic] +fn copy_from_slice_panics_if_different_length_2() { + let mut data = [b'b', b'a', b'r']; + + let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + slice.copy_from_slice(b"abcd"); +} diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 6b106a6..b9e6ce4 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -461,6 +461,7 @@ fn reserve_allocates_at_least_original_capacity() { } #[test] +#[cfg_attr(miri, ignore)] // Miri is too slow fn reserve_max_original_capacity_value() { const SIZE: usize = 128 * 1024; @@ -608,15 +609,15 @@ fn advance_past_len() { #[test] // Only run these tests on little endian systems. CI uses qemu for testing -// little endian... and qemu doesn't really support threading all that well. -#[cfg(target_endian = "little")] +// big endian... and qemu doesn't really support threading all that well. +#[cfg(any(miri, target_endian = "little"))] fn stress() { // Tests promoting a buffer from a vec -> shared in a concurrent situation use std::sync::{Arc, Barrier}; use std::thread; const THREADS: usize = 8; - const ITERS: usize = 1_000; + const ITERS: usize = if cfg!(miri) { 100 } else { 1_000 }; for i in 0..ITERS { let data = [i as u8; 256]; @@ -912,20 +913,20 @@ fn bytes_buf_mut_advance() { let mut bytes = BytesMut::with_capacity(1024); unsafe { - let ptr = bytes.bytes_mut().as_ptr(); - assert_eq!(1024, bytes.bytes_mut().len()); + let ptr = bytes.chunk_mut().as_mut_ptr(); + assert_eq!(1024, bytes.chunk_mut().len()); bytes.advance_mut(10); - let next = bytes.bytes_mut().as_ptr(); - assert_eq!(1024 - 10, bytes.bytes_mut().len()); + let next = bytes.chunk_mut().as_mut_ptr(); + assert_eq!(1024 - 10, bytes.chunk_mut().len()); assert_eq!(ptr.offset(10), next); // advance to the end bytes.advance_mut(1024 - 10); // The buffer size is doubled - assert_eq!(1024, bytes.bytes_mut().len()); + assert_eq!(1024, bytes.chunk_mut().len()); } } diff --git a/tests/test_bytes_odd_alloc.rs b/tests/test_bytes_odd_alloc.rs index 4ce424b..04ba7c2 100644 --- a/tests/test_bytes_odd_alloc.rs +++ b/tests/test_bytes_odd_alloc.rs @@ -1,6 +1,8 @@ //! Test using `Bytes` with an allocator that hands out "odd" pointers for //! vectors (pointers where the LSB is set). +#![cfg(not(miri))] // Miri does not support custom allocators (also, Miri is "odd" by default with 50% chance) + use std::alloc::{GlobalAlloc, Layout, System}; use std::ptr; diff --git a/tests/test_chain.rs b/tests/test_chain.rs index 6dbc45d..500ccd4 100644 --- a/tests/test_chain.rs +++ b/tests/test_chain.rs @@ -1,6 +1,5 @@ #![warn(rust_2018_idioms)] -use bytes::buf::{BufExt, BufMutExt}; use bytes::{Buf, BufMut, Bytes}; #[cfg(feature = "std")] use std::io::IoSlice; @@ -10,7 +9,7 @@ fn collect_two_bufs() { let a = Bytes::from(&b"hello"[..]); let b = Bytes::from(&b"world"[..]); - let res = a.chain(b).to_bytes(); + let res = a.chain(b).copy_to_bytes(10); assert_eq!(res, &b"helloworld"[..]); } @@ -63,7 +62,7 @@ fn vectored_read() { IoSlice::new(b4), ]; - assert_eq!(2, buf.bytes_vectored(&mut iovecs)); + assert_eq!(2, buf.chunks_vectored(&mut iovecs)); assert_eq!(iovecs[0][..], b"hello"[..]); assert_eq!(iovecs[1][..], b"world"[..]); assert_eq!(iovecs[2][..], b""[..]); @@ -84,7 +83,7 @@ fn vectored_read() { IoSlice::new(b4), ]; - assert_eq!(2, buf.bytes_vectored(&mut iovecs)); + assert_eq!(2, buf.chunks_vectored(&mut iovecs)); assert_eq!(iovecs[0][..], b"llo"[..]); assert_eq!(iovecs[1][..], b"world"[..]); assert_eq!(iovecs[2][..], b""[..]); @@ -105,7 +104,7 @@ fn vectored_read() { IoSlice::new(b4), ]; - assert_eq!(1, buf.bytes_vectored(&mut iovecs)); + assert_eq!(1, buf.chunks_vectored(&mut iovecs)); assert_eq!(iovecs[0][..], b"world"[..]); assert_eq!(iovecs[1][..], b""[..]); assert_eq!(iovecs[2][..], b""[..]); @@ -126,7 +125,7 @@ fn vectored_read() { IoSlice::new(b4), ]; - assert_eq!(1, buf.bytes_vectored(&mut iovecs)); + assert_eq!(1, buf.chunks_vectored(&mut iovecs)); assert_eq!(iovecs[0][..], b"ld"[..]); assert_eq!(iovecs[1][..], b""[..]); assert_eq!(iovecs[2][..], b""[..]); diff --git a/tests/test_reader.rs b/tests/test_reader.rs index 10b480f..897aff6 100644 --- a/tests/test_reader.rs +++ b/tests/test_reader.rs @@ -3,13 +3,13 @@ use std::io::{BufRead, Read}; -use bytes::buf::BufExt; +use bytes::Buf; #[test] fn read() { let buf1 = &b"hello "[..]; let buf2 = &b"world"[..]; - let buf = BufExt::chain(buf1, buf2); // Disambiguate with Read::chain + let buf = Buf::chain(buf1, buf2); // Disambiguate with Read::chain let mut buffer = Vec::new(); buf.reader().read_to_end(&mut buffer).unwrap(); assert_eq!(b"hello world", &buffer[..]); @@ -19,7 +19,7 @@ fn read() { fn buf_read() { let buf1 = &b"hell"[..]; let buf2 = &b"o\nworld"[..]; - let mut reader = BufExt::chain(buf1, buf2).reader(); + let mut reader = Buf::chain(buf1, buf2).reader(); let mut line = String::new(); reader.read_line(&mut line).unwrap(); assert_eq!("hello\n", &line); diff --git a/tests/test_take.rs b/tests/test_take.rs index 0afb28b..a23a29e 100644 --- a/tests/test_take.rs +++ b/tests/test_take.rs @@ -1,6 +1,6 @@ #![warn(rust_2018_idioms)] -use bytes::buf::{Buf, BufExt}; +use bytes::buf::Buf; #[test] fn long_take() { @@ -8,5 +8,5 @@ fn long_take() { // overrun the buffer. Regression test for #138. let buf = b"hello world".take(100); assert_eq!(11, buf.remaining()); - assert_eq!(b"hello world", buf.bytes()); + assert_eq!(b"hello world", buf.chunk()); } |