From ed244d3b548d44d6bdc9d0fec5d0c21f9f898753 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 22 Jul 2018 19:30:41 -0700 Subject: [PATCH 01/19] Bump version to v0.4.9 (#220) --- CHANGELOG.md | 5 +++++ Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42a4025..1e87d35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.4.9 (July 12, 2018) + +* Add 128 bit number support behind a feature flag (#209). +* Implement `IntoBuf` for `&mut [u8]` + # 0.4.8 (May 25, 2018) * Fix panic in `BytesMut` `FromIterator` implementation. diff --git a/Cargo.toml b/Cargo.toml index fcc7397..9cfed61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bytes" -version = "0.4.8" # don't forget to update html_root_url +version = "0.4.9" # don't forget to update html_root_url license = "MIT" authors = ["Carl Lerche "] description = "Types and traits for working with bytes" diff --git a/src/lib.rs b/src/lib.rs index 4f77c09..eccb8a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,7 @@ //! and `BufMut` are infallible. #![deny(warnings, missing_docs, missing_debug_implementations)] -#![doc(html_root_url = "https://docs.rs/bytes/0.4.8")] +#![doc(html_root_url = "https://docs.rs/bytes/0.4.9")] extern crate byteorder; extern crate iovec; From 79f05591c9fe6d40affa3882a8fc666e13c47bcd Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Sat, 1 Sep 2018 21:57:31 -0500 Subject: [PATCH 02/19] Add a subslice function for Bytes (#198) (#208) This lets us take Bytes and a &[u8] slice that is contained in it, and create a new Bytes that corresponds to that subset slice. Closes #198 --- src/bytes.rs | 40 +++++++++++++++++++++++++++++++++ tests/test_bytes.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/bytes.rs b/src/bytes.rs index 89244dd..1cc168f 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -576,6 +576,46 @@ impl Bytes { self.slice(0, end) } + /// Returns a slice of self that is equivalent to the given `subset`. + /// + /// When processing a `Bytes` buffer with other tools, one often gets a + /// `&[u8]` which is in fact a slice of the `Bytes`, i.e. a subset of it. + /// This function turns that `&[u8]` into another `Bytes`, as if one had + /// called `self.slice()` with the offsets that correspond to `subset`. + /// + /// This operation is `O(1)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let bytes = Bytes::from(&b"012345678"[..]); + /// let as_slice = bytes.as_ref(); + /// let subset = &as_slice[2..6]; + /// let subslice = bytes.slice_ref(&subset); + /// assert_eq!(&subslice[..], b"2345"); + /// ``` + /// + /// # Panics + /// + /// Requires that the given `sub` slice is in fact contained within the + /// `Bytes` buffer; otherwise this function will panic. + pub fn slice_ref(&self, subset: &[u8]) -> Bytes { + let bytes_p = self.as_ptr() as usize; + let bytes_len = self.len(); + + let sub_p = subset.as_ptr() as usize; + let sub_len = subset.len(); + + assert!(sub_p >= bytes_p); + assert!(sub_p + sub_len <= bytes_p + bytes_len); + + let sub_offset = sub_p - bytes_p; + + self.slice(sub_offset, sub_offset + sub_len) + } + /// Splits the bytes into two at the given index. /// /// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes` diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index c0cba6b..4cf340e 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -717,3 +717,57 @@ fn from_iter_no_size_hint() { assert_eq!(&actual[..], &expect[..]); } + +fn test_slice_ref(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) { + let slice = &(bytes.as_ref()[start..end]); + let sub = bytes.slice_ref(&slice); + assert_eq!(&sub[..], expected); +} + +#[test] +fn slice_ref_works() { + let bytes = Bytes::from(&b"012345678"[..]); + + test_slice_ref(&bytes, 0, 0, b""); + test_slice_ref(&bytes, 0, 3, b"012"); + test_slice_ref(&bytes, 2, 6, b"2345"); + test_slice_ref(&bytes, 7, 9, b"78"); + test_slice_ref(&bytes, 9, 9, b""); +} + + +#[test] +fn slice_ref_empty() { + let bytes = Bytes::from(&b""[..]); + let slice = &(bytes.as_ref()[0..0]); + + let sub = bytes.slice_ref(&slice); + assert_eq!(&sub[..], b""); +} + +#[test] +#[should_panic] +fn slice_ref_catches_not_a_subset() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b"012345"[0..4]; + + bytes.slice_ref(slice); +} + +#[test] +#[should_panic] +fn slice_ref_catches_not_an_empty_subset() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b""[0..0]; + + bytes.slice_ref(slice); +} + +#[test] +#[should_panic] +fn empty_slice_ref_catches_not_an_empty_subset() { + let bytes = Bytes::from(&b""[..]); + let slice = &b""[0..0]; + + bytes.slice_ref(slice); +} From ad35fbef035da3bc0b18b2042ae19cf7358fec6e Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 3 Sep 2018 10:23:00 -0700 Subject: [PATCH 03/19] implement `Buf` and `BufMut` for `Either` (#225) --- .travis.yml | 3 ++ Cargo.toml | 1 + src/either.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +++ 4 files changed, 97 insertions(+) create mode 100644 src/either.rs diff --git a/.travis.yml b/.travis.yml index 3deb61f..2e8ab18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,9 @@ matrix: # 128 bit numbers - env: EXTRA_ARGS="--features i128" + # `Either` impls + - env: EXTRA_ARGS="--features either" + # WASM support - rust: beta script: diff --git a/Cargo.toml b/Cargo.toml index 9cfed61..af9a794 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ features = ["i128"] byteorder = "1.1.0" iovec = "0.1" serde = { version = "1.0", optional = true } +either = { version = "1.5", default-features = false, optional = true } [dev-dependencies] serde_test = "1.0" diff --git a/src/either.rs b/src/either.rs new file mode 100644 index 0000000..53a2775 --- /dev/null +++ b/src/either.rs @@ -0,0 +1,89 @@ +extern crate either; + +use {Buf, BufMut}; + +use self::either::Either; +use self::either::Either::*; +use iovec::IoVec; + +impl Buf for Either +where + L: Buf, + R: Buf, +{ + fn remaining(&self) -> usize { + match *self { + Left(ref b) => b.remaining(), + Right(ref b) => b.remaining(), + } + } + + fn bytes(&self) -> &[u8] { + match *self { + Left(ref b) => b.bytes(), + Right(ref b) => b.bytes(), + } + } + + fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { + match *self { + Left(ref b) => b.bytes_vec(dst), + Right(ref b) => b.bytes_vec(dst), + } + } + + fn advance(&mut self, cnt: usize) { + match *self { + Left(ref mut b) => b.advance(cnt), + Right(ref mut b) => b.advance(cnt), + } + } + + fn copy_to_slice(&mut self, dst: &mut [u8]) { + match *self { + Left(ref mut b) => b.copy_to_slice(dst), + Right(ref mut b) => b.copy_to_slice(dst), + } + } +} + +impl BufMut for Either +where + L: BufMut, + R: BufMut, +{ + fn remaining_mut(&self) -> usize { + match *self { + Left(ref b) => b.remaining_mut(), + Right(ref b) => b.remaining_mut(), + } + } + + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + match *self { + Left(ref mut b) => b.bytes_mut(), + Right(ref mut b) => b.bytes_mut(), + } + } + + unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { + match *self { + Left(ref mut b) => b.bytes_vec_mut(dst), + Right(ref mut b) => b.bytes_vec_mut(dst), + } + } + + unsafe fn advance_mut(&mut self, cnt: usize) { + match *self { + Left(ref mut b) => b.advance_mut(cnt), + Right(ref mut b) => b.advance_mut(cnt), + } + } + + fn put_slice(&mut self, src: &[u8]) { + match *self { + Left(ref mut b) => b.put_slice(src), + Right(ref mut b) => b.put_slice(src), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index eccb8a3..b007940 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,3 +99,7 @@ pub use byteorder::{ByteOrder, BigEndian, LittleEndian}; #[cfg(feature = "serde")] #[doc(hidden)] pub mod serde; + +// Optional `Either` support +#[cfg(feature = "either")] +mod either; From f09c51c34e533a493c9e97018de6a0a33daf080e Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 3 Sep 2018 13:36:13 -0700 Subject: [PATCH 04/19] White list allocation (#226) --- ci/tsan | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/tsan b/ci/tsan index 657d426..2957406 100644 --- a/ci/tsan +++ b/ci/tsan @@ -9,6 +9,9 @@ race:arc*Weak*drop # rust runtime logic. race:std*mpsc_queue +# Some test runtime races. Allocation should be race free +race:alloc::alloc + # Not sure why this is warning, but it is in the test harness and not the library. race:TestEvent*clone race:test::run_tests_console::*closure From 456221d16521cf54cea0e6569669e47120a1b738 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Tue, 4 Sep 2018 13:31:26 -0700 Subject: [PATCH 05/19] Bump version to v0.4.10 (#227) --- CHANGELOG.md | 5 +++++ Cargo.toml | 9 +++++++-- src/lib.rs | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e87d35..c58c040 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.4.10 (September 4, 2018) + +* impl `Buf` and `BufMut` for `Either` (#225). +* Add `Bytes::slice_ref` (#208). + # 0.4.9 (July 12, 2018) * Add 128 bit number support behind a feature flag (#209). diff --git a/Cargo.toml b/Cargo.toml index af9a794..0a2ff7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,16 @@ [package] name = "bytes" -version = "0.4.9" # don't forget to update html_root_url +# When releasing to crates.io: +# - Update html_root_url. +# - Update CHANGELOG.md. +# - Update doc URL. +# - Create "v0.4.x" git tag. +version = "0.4.10" license = "MIT" authors = ["Carl Lerche "] description = "Types and traits for working with bytes" -documentation = "https://carllerche.github.io/bytes/bytes" +documentation = "https://docs.rs/bytes/0.4.10/bytes" homepage = "https://github.com/carllerche/bytes" repository = "https://github.com/carllerche/bytes" readme = "README.md" diff --git a/src/lib.rs b/src/lib.rs index b007940..9cc6eee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,7 @@ //! and `BufMut` are infallible. #![deny(warnings, missing_docs, missing_debug_implementations)] -#![doc(html_root_url = "https://docs.rs/bytes/0.4.9")] +#![doc(html_root_url = "https://docs.rs/bytes/0.4.10")] extern crate byteorder; extern crate iovec; From e5304410a48fee8d78bd0422c15b65b2361359ff Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sat, 17 Nov 2018 07:27:00 -0800 Subject: [PATCH 06/19] Whitelist false positive std (#234) --- ci/tsan | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci/tsan b/ci/tsan index 2957406..9cc5484 100644 --- a/ci/tsan +++ b/ci/tsan @@ -22,3 +22,7 @@ race:__call_tls_dtors # `is_inline_or_static` is explicitly called concurrently without synchronization. # The safety explanation can be found in a comment. race:Inner::is_inline_or_static + +# This ignores a false positive caused by `thread::park()`/`thread::unpark()`. +# See: https://github.com/rust-lang/rust/pull/54806#issuecomment-436193353 +race:pthread_cond_destroy From e64a123d002e56626580cb51ae7e729e6574ce59 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 17 Nov 2018 16:51:28 +0100 Subject: [PATCH 07/19] Bring more attention to short reads/slices on Buff/BuffMut (#231) The property the Buff and BuffMut can return shorter slice is quite an important detail. Nevertheless, while it is mentioned in the documentation, the wording makes it relatively easy to overlook. This tries to bring more attention to it. --- src/buf/buf.rs | 3 ++- src/buf/buf_mut.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/buf/buf.rs b/src/buf/buf.rs index b72c8d9..dc20567 100644 --- a/src/buf/buf.rs +++ b/src/buf/buf.rs @@ -91,7 +91,8 @@ pub trait Buf { fn remaining(&self) -> usize; /// Returns a slice starting at the current position and of length between 0 - /// and `Buf::remaining()`. + /// and `Buf::remaining()`. Note that this *can* return shorter slice (this allows + /// non-continuous internal representation). /// /// This is a lower level function. Most operations are done with other /// functions. diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 71dbda9..7f3c1f7 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -121,7 +121,8 @@ pub trait BufMut { } /// Returns a mutable slice starting at the current BufMut position and of - /// length between 0 and `BufMut::remaining_mut()`. + /// length between 0 and `BufMut::remaining_mut()`. Note that this *can* be shorter than the + /// whole remainder of the buffer (this allows non-continuous implementation). /// /// This is a lower level function. Most operations are done with other /// functions. From 7c3085aaec243feb26ee4ebe867b0acac6b62d3b Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 17 Nov 2018 16:51:41 +0100 Subject: [PATCH 08/19] The Reader can implement BufReader naturally (#232) There's no reason the user should be forced to wrap it in BufReader in case the trait is needed, because the Reader has all the bits for supporting it naturally. --- src/buf/reader.rs | 9 +++++++++ tests/test_reader.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/test_reader.rs diff --git a/src/buf/reader.rs b/src/buf/reader.rs index 59f9c33..f1154da 100644 --- a/src/buf/reader.rs +++ b/src/buf/reader.rs @@ -86,3 +86,12 @@ impl io::Read for Reader { Ok(len) } } + +impl io::BufRead for Reader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Ok(self.buf.bytes()) + } + fn consume(&mut self, amt: usize) { + self.buf.advance(amt) + } +} diff --git a/tests/test_reader.rs b/tests/test_reader.rs new file mode 100644 index 0000000..7103f35 --- /dev/null +++ b/tests/test_reader.rs @@ -0,0 +1,28 @@ +extern crate bytes; + +use std::io::{BufRead, Cursor, Read}; + +use bytes::Buf; + +#[test] +fn read() { + let buf1 = Cursor::new(b"hello "); + let buf2 = Cursor::new(b"world"); + 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[..]); +} + +#[test] +fn buf_read() { + let buf1 = Cursor::new(b"hell"); + let buf2 = Cursor::new(b"o\nworld"); + let mut reader = Buf::chain(buf1, buf2).reader(); + let mut line = String::new(); + reader.read_line(&mut line).unwrap(); + assert_eq!("hello\n", &line); + line.clear(); + reader.read_line(&mut line).unwrap(); + assert_eq!("world", &line); +} From c6c5b8fb541b5fea581706d04b2525d18ce00ebe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 16:51:50 +0100 Subject: [PATCH 09/19] Use raw pointers for potentially racy loads (#233) Shared references assert immutability, so any concurrent access would be UB disregarding data race concerns. --- src/bytes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index 1cc168f..3d6fb31 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2438,7 +2438,7 @@ impl Inner { #[inline] fn imp(arc: &AtomicPtr) -> usize { unsafe { - let p: &u8 = mem::transmute(arc); + let p: *const u8 = mem::transmute(arc); (*p as usize) & KIND_MASK } } @@ -2447,7 +2447,7 @@ impl Inner { #[inline] fn imp(arc: &AtomicPtr) -> usize { unsafe { - let p: &usize = mem::transmute(arc); + let p: *const usize = mem::transmute(arc); *p & KIND_MASK } } From b3248c8807684dbc3996d61fff47f9a630511662 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sat, 17 Nov 2018 14:33:25 -0800 Subject: [PATCH 10/19] Bump version to v0.4.11 (#235) --- CHANGELOG.md | 6 ++++++ Cargo.toml | 4 ++-- src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c58c040..1e090c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.4.11 (November 17, 2018) + +* Use raw pointers for potentially racy loads (#233). +* Implement `BufRead` for `buf::Reader` (#232). +* Documentation tweaks (#234). + # 0.4.10 (September 4, 2018) * impl `Buf` and `BufMut` for `Either` (#225). diff --git a/Cargo.toml b/Cargo.toml index 0a2ff7f..ac911f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,11 @@ name = "bytes" # - Update CHANGELOG.md. # - Update doc URL. # - Create "v0.4.x" git tag. -version = "0.4.10" +version = "0.4.11" license = "MIT" authors = ["Carl Lerche "] description = "Types and traits for working with bytes" -documentation = "https://docs.rs/bytes/0.4.10/bytes" +documentation = "https://docs.rs/bytes/0.4.11/bytes" homepage = "https://github.com/carllerche/bytes" repository = "https://github.com/carllerche/bytes" readme = "README.md" diff --git a/src/lib.rs b/src/lib.rs index 9cc6eee..54c5b81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,7 @@ //! and `BufMut` are infallible. #![deny(warnings, missing_docs, missing_debug_implementations)] -#![doc(html_root_url = "https://docs.rs/bytes/0.4.10")] +#![doc(html_root_url = "https://docs.rs/bytes/0.4.11")] extern crate byteorder; extern crate iovec; From 9504447adc3459ee0342efa9b3fdef684a211d6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 07:49:35 +0100 Subject: [PATCH 11/19] Be clear about Inner::kind being deliberate UB (#236) --- src/bytes.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bytes.rs b/src/bytes.rs index 3d6fb31..d7071d7 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2429,6 +2429,10 @@ impl Inner { // bits, so even without any explicit atomic operations, reading the // flag will be correct. // + // This is undefind behavior due to a data race, but experimental + // evidence shows that it works in practice (discussion: + // https://internals.rust-lang.org/t/bit-wise-reasoning-for-atomic-accesses/8853). + // // This function is very critical performance wise as it is called for // every operation. Performing an atomic load would mess with the // compiler's ability to optimize. Simple benchmarks show up to a 10% From 42b669690af1f358dd5234beb5078ebdf25b3e02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Dec 2018 20:07:20 +0100 Subject: [PATCH 12/19] use raw ptr for potentially racy load (#240) --- src/bytes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bytes.rs b/src/bytes.rs index d7071d7..fb58a77 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2467,7 +2467,7 @@ impl Inner { // function. let prev = unsafe { let p: &AtomicPtr = &self.arc; - let p: &usize = mem::transmute(p); + let p: *const usize = mem::transmute(p); *p }; From f3b363a385c609f3bfb1161b8028ed84034a6020 Mon Sep 17 00:00:00 2001 From: Dax Huiberts Date: Mon, 28 Jan 2019 19:06:28 +0100 Subject: [PATCH 13/19] Fix typo in bytes.rs (#243) --- src/bytes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bytes.rs b/src/bytes.rs index fb58a77..cb1aae4 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -273,7 +273,7 @@ pub struct BytesMut { // The rest of `arc`'s bytes are used as part of the inline buffer, which means // that those bytes need to be located next to the `ptr`, `len`, and `cap` // fields, which make up the rest of the inline buffer. This requires special -// casing the layout of `Inner` depending on if the target platform is bit or +// casing the layout of `Inner` depending on if the target platform is big or // little endian. // // On little endian platforms, the `arc` field must be the first field in the From 55dfea8c18fcb412702319b58b4407248a5115ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=97=E6=B5=A6=E6=9C=88?= Date: Thu, 31 Jan 2019 03:05:15 +0800 Subject: [PATCH 14/19] Impl FromIterator<&'a u8> for `BytesMut`/`Bytes` (#244) --- src/bytes.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bytes.rs b/src/bytes.rs index cb1aae4..db6cba7 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -926,6 +926,18 @@ impl FromIterator for Bytes { } } +impl<'a> FromIterator<&'a u8> for BytesMut { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_iter(into_iter.into_iter().map(|b| *b)) + } +} + +impl<'a> FromIterator<&'a u8> for Bytes { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_iter(into_iter).freeze() + } +} + impl PartialEq for Bytes { fn eq(&self, other: &Bytes) -> bool { self.inner.as_ref() == other.inner.as_ref() From e13d2a783e29cc973fd21023b24896305d3d2fbc Mon Sep 17 00:00:00 2001 From: Sangguk Lee Date: Thu, 28 Feb 2019 03:41:11 +0900 Subject: [PATCH 15/19] Use constants in bytes.rs test code (#247) --- src/bytes.rs | 54 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index db6cba7..e155931 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2586,35 +2586,51 @@ fn original_capacity_from_repr(repr: usize) -> usize { #[test] fn test_original_capacity_to_repr() { - for &cap in &[0, 1, 16, 1000] { - assert_eq!(0, original_capacity_to_repr(cap)); - } + assert_eq!(original_capacity_to_repr(0), 0); - for &cap in &[1024, 1025, 1100, 2000, 2047] { - assert_eq!(1, original_capacity_to_repr(cap)); - } + let max_width = 32; - for &cap in &[2048, 2049] { - assert_eq!(2, original_capacity_to_repr(cap)); - } + for width in 1..(max_width + 1) { + let cap = 1 << width - 1; - // TODO: more + let expected = if width < MIN_ORIGINAL_CAPACITY_WIDTH { + 0 + } else if width < MAX_ORIGINAL_CAPACITY_WIDTH { + width - MIN_ORIGINAL_CAPACITY_WIDTH + } else { + MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH + }; - for &cap in &[65536, 65537, 68000, 1 << 17, 1 << 18, 1 << 20, 1 << 30] { - assert_eq!(7, original_capacity_to_repr(cap), "cap={}", cap); + assert_eq!(original_capacity_to_repr(cap), expected); + + if width > 1 { + assert_eq!(original_capacity_to_repr(cap + 1), expected); + } + + // MIN_ORIGINAL_CAPACITY_WIDTH must be bigger than 7 to pass tests below + if width == MIN_ORIGINAL_CAPACITY_WIDTH + 1 { + assert_eq!(original_capacity_to_repr(cap - 24), expected - 1); + assert_eq!(original_capacity_to_repr(cap + 76), expected); + } else if width == MIN_ORIGINAL_CAPACITY_WIDTH + 2 { + assert_eq!(original_capacity_to_repr(cap - 1), expected - 1); + assert_eq!(original_capacity_to_repr(cap - 48), expected - 1); + } } } #[test] fn test_original_capacity_from_repr() { assert_eq!(0, original_capacity_from_repr(0)); - assert_eq!(1024, original_capacity_from_repr(1)); - assert_eq!(1024 * 2, original_capacity_from_repr(2)); - assert_eq!(1024 * 4, original_capacity_from_repr(3)); - assert_eq!(1024 * 8, original_capacity_from_repr(4)); - assert_eq!(1024 * 16, original_capacity_from_repr(5)); - assert_eq!(1024 * 32, original_capacity_from_repr(6)); - assert_eq!(1024 * 64, original_capacity_from_repr(7)); + + let min_cap = 1 << MIN_ORIGINAL_CAPACITY_WIDTH; + + assert_eq!(min_cap, original_capacity_from_repr(1)); + assert_eq!(min_cap * 2, original_capacity_from_repr(2)); + assert_eq!(min_cap * 4, original_capacity_from_repr(3)); + assert_eq!(min_cap * 8, original_capacity_from_repr(4)); + assert_eq!(min_cap * 16, original_capacity_from_repr(5)); + assert_eq!(min_cap * 32, original_capacity_from_repr(6)); + assert_eq!(min_cap * 64, original_capacity_from_repr(7)); } unsafe impl Send for Inner {} From 0e8b440650fffe49f1ecf591e531000ecd4440e6 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 6 Mar 2019 20:46:42 +0100 Subject: [PATCH 16/19] Implementation of Buf for VecDeque (#249) --- src/buf/mod.rs | 1 + src/buf/vec_deque.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/buf/vec_deque.rs diff --git a/src/buf/mod.rs b/src/buf/mod.rs index 1f74e0a..35b4857 100644 --- a/src/buf/mod.rs +++ b/src/buf/mod.rs @@ -24,6 +24,7 @@ mod into_buf; mod iter; mod reader; mod take; +mod vec_deque; mod writer; pub use self::buf::Buf; diff --git a/src/buf/vec_deque.rs b/src/buf/vec_deque.rs new file mode 100644 index 0000000..1cd650f --- /dev/null +++ b/src/buf/vec_deque.rs @@ -0,0 +1,39 @@ +use std::collections::VecDeque; + +use super::Buf; + +impl Buf for VecDeque { + fn remaining(&self) -> usize { + self.len() + } + + fn bytes(&self) -> &[u8] { + let (s1, s2) = self.as_slices(); + if s1.is_empty() { + s2 + } else { + s1 + } + } + + fn advance(&mut self, cnt: usize) { + self.drain(..cnt); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hello_world() { + let mut buffer: VecDeque = VecDeque::new(); + buffer.extend(b"hello world"); + assert_eq!(11, buffer.remaining()); + assert_eq!(b"hello world", buffer.bytes()); + buffer.advance(6); + assert_eq!(b"world", buffer.bytes()); + buffer.extend(b" piece"); + assert_eq!(b"world piece" as &[u8], &buffer.collect::>()[..]); + } +} From 4948b1053b1af8f474a107b958dd0086ada06b17 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 6 Mar 2019 12:42:20 -0800 Subject: [PATCH 17/19] Bump version to v0.4.12 (#250) --- CHANGELOG.md | 6 ++++++ Cargo.toml | 4 ++-- README.md | 6 +++--- src/lib.rs | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e090c7..881b6f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.4.12 (March 6, 2018) + +### Added +- Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244). +- Implement `Buf` for `VecDeque` (#249). + # 0.4.11 (November 17, 2018) * Use raw pointers for potentially racy loads (#233). diff --git a/Cargo.toml b/Cargo.toml index ac911f1..99331b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,11 @@ name = "bytes" # - Update CHANGELOG.md. # - Update doc URL. # - Create "v0.4.x" git tag. -version = "0.4.11" +version = "0.4.12" license = "MIT" authors = ["Carl Lerche "] description = "Types and traits for working with bytes" -documentation = "https://docs.rs/bytes/0.4.11/bytes" +documentation = "https://docs.rs/bytes/0.4.12/bytes" homepage = "https://github.com/carllerche/bytes" repository = "https://github.com/carllerche/bytes" readme = "README.md" diff --git a/README.md b/README.md index 3b2a80b..0135974 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A utility library for working with bytes. [![Crates.io](https://img.shields.io/crates/v/bytes.svg?maxAge=2592000)](https://crates.io/crates/bytes) [![Build Status](https://travis-ci.org/carllerche/bytes.svg?branch=master)](https://travis-ci.org/carllerche/bytes) -[Documentation](https://carllerche.github.io/bytes/bytes/index.html) +[Documentation](https://docs.rs/bytes/0.4.12/bytes/) ## Usage @@ -13,7 +13,7 @@ To use `bytes`, first add this to your `Cargo.toml`: ```toml [dependencies] -bytes = "0.4" +bytes = "0.4.12" ``` Next, add this to your crate: @@ -30,7 +30,7 @@ Serde support is optional and disabled by default. To enable use the feature `se ```toml [dependencies] -bytes = { version = "0.4", features = ["serde"] } +bytes = { version = "0.4.12", features = ["serde"] } ``` ## License diff --git a/src/lib.rs b/src/lib.rs index 54c5b81..a4f1573 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,7 @@ //! and `BufMut` are infallible. #![deny(warnings, missing_docs, missing_debug_implementations)] -#![doc(html_root_url = "https://docs.rs/bytes/0.4.11")] +#![doc(html_root_url = "https://docs.rs/bytes/0.4.12")] extern crate byteorder; extern crate iovec; From e0e30f00a1248b1de59405da66cd871ccace4f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=97=E6=B5=A6=E6=9C=88?= Date: Sat, 30 Mar 2019 04:54:25 +0800 Subject: [PATCH 18/19] Fix a typo in CHANGELOG.md (#251) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 881b6f6..f846427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.4.12 (March 6, 2018) +# 0.4.12 (March 6, 2019) ### Added - Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244). From d43e283e5ed520e54df2428f2cf9a7c13c79ff49 Mon Sep 17 00:00:00 2001 From: Pavel Strakhov Date: Wed, 3 Apr 2019 02:24:30 +0300 Subject: [PATCH 19/19] Panic in BytesMut::split_to when out of bounds (#252) (#253) --- src/bytes.rs | 2 ++ tests/test_bytes.rs | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index e155931..a9aefa9 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1265,6 +1265,8 @@ impl BytesMut { /// /// Panics if `at > len`. pub fn split_to(&mut self, at: usize) -> BytesMut { + assert!(at <= self.len()); + BytesMut { inner: self.inner.split_to(at), } diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 4cf340e..e188354 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -258,15 +258,10 @@ fn split_to_oob_mut() { } #[test] +#[should_panic] fn split_to_uninitialized() { let mut bytes = BytesMut::with_capacity(1024); - let other = bytes.split_to(128); - - assert_eq!(bytes.len(), 0); - assert_eq!(bytes.capacity(), 896); - - assert_eq!(other.len(), 0); - assert_eq!(other.capacity(), 128); + let _other = bytes.split_to(128); } #[test]