From 79f05591c9fe6d40affa3882a8fc666e13c47bcd Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Sat, 1 Sep 2018 21:57:31 -0500 Subject: 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 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'src/bytes.rs') 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` -- cgit v1.2.3 From c6c5b8fb541b5fea581706d04b2525d18ce00ebe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 16:51:50 +0100 Subject: 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(-) (limited to 'src/bytes.rs') 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 } } -- cgit v1.2.3 From 9504447adc3459ee0342efa9b3fdef684a211d6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 07:49:35 +0100 Subject: Be clear about Inner::kind being deliberate UB (#236) --- src/bytes.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/bytes.rs') 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% -- cgit v1.2.3 From 42b669690af1f358dd5234beb5078ebdf25b3e02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Dec 2018 20:07:20 +0100 Subject: use raw ptr for potentially racy load (#240) --- src/bytes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bytes.rs') 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 }; -- cgit v1.2.3 From f3b363a385c609f3bfb1161b8028ed84034a6020 Mon Sep 17 00:00:00 2001 From: Dax Huiberts Date: Mon, 28 Jan 2019 19:06:28 +0100 Subject: Fix typo in bytes.rs (#243) --- src/bytes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bytes.rs') 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 -- cgit v1.2.3 From 55dfea8c18fcb412702319b58b4407248a5115ca Mon Sep 17 00:00:00 2001 From: 南浦月 Date: Thu, 31 Jan 2019 03:05:15 +0800 Subject: Impl FromIterator<&'a u8> for `BytesMut`/`Bytes` (#244) --- src/bytes.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/bytes.rs') 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() -- cgit v1.2.3 From e13d2a783e29cc973fd21023b24896305d3d2fbc Mon Sep 17 00:00:00 2001 From: Sangguk Lee Date: Thu, 28 Feb 2019 03:41:11 +0900 Subject: Use constants in bytes.rs test code (#247) --- src/bytes.rs | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'src/bytes.rs') 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; + + 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 + }; - // TODO: more + assert_eq!(original_capacity_to_repr(cap), expected); - for &cap in &[65536, 65537, 68000, 1 << 17, 1 << 18, 1 << 20, 1 << 30] { - assert_eq!(7, original_capacity_to_repr(cap), "cap={}", cap); + 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 {} -- cgit v1.2.3 From d43e283e5ed520e54df2428f2cf9a7c13c79ff49 Mon Sep 17 00:00:00 2001 From: Pavel Strakhov Date: Wed, 3 Apr 2019 02:24:30 +0300 Subject: 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(-) (limited to 'src/bytes.rs') 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] -- cgit v1.2.3