From afb8a3256939fb04533d59a41bde6611927058e0 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Thu, 31 May 2018 12:22:46 -0500 Subject: [PATCH] Add a subslice function for Bytes (#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 465023504..61c194c68 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -588,6 +588,46 @@ impl Bytes { self.slice(0, end) } + /// Returns a slice of self that is equivalent to the given `sub`. + /// + /// When processing a `Bytes` buffer with other tools, one often + /// gets a `&[u8]` which is in fact a slice of the `Bytes`. This + /// function turns that `&[u8]` into another `Bytes`, as if one had + /// called `self.slice()` with the offsets that correspond to `sub`. + /// + /// This operation is `O(1)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let bytes = Bytes::from(&b"012345678"[..]); + /// let as_slice = bytes.as_ref(); + /// let sub = &as_slice[2..6]; + /// let subslice = bytes.subslice(&sub); + /// assert_eq!(&subslice[..], b"2345"); + /// ``` + /// + /// # Panics + /// + /// Requires that the given `sub` slice is in fact contained + /// within the `Bytes` buffer; otherwise subslicing will panic. + pub fn subslice(&self, sub: &[u8]) -> Bytes { + let bytes_p = self.as_ptr() as usize; + let bytes_len = self.len(); + + let sub_p = sub.as_ptr() as usize; + let sub_len = sub.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 ccc89fa0a..862dc6816 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -844,3 +844,57 @@ fn from_iter_no_size_hint() { assert_eq!(&actual[..], &expect[..]); } + +fn test_subslice(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) { + let slice = &(bytes.as_ref()[start..end]); + let sub = bytes.subslice(&slice); + assert_eq!(&sub[..], expected); +} + +#[test] +fn subslice_works() { + let bytes = Bytes::from(&b"012345678"[..]); + + test_subslice(&bytes, 0, 0, b""); + test_subslice(&bytes, 0, 3, b"012"); + test_subslice(&bytes, 2, 6, b"2345"); + test_subslice(&bytes, 7, 9, b"78"); + test_subslice(&bytes, 9, 9, b""); +} + + +#[test] +fn subslice_empty() { + let bytes = Bytes::from(&b""[..]); + let slice = &(bytes.as_ref()[0..0]); + + let sub = bytes.subslice(&slice); + assert_eq!(&sub[..], b""); +} + +#[test] +#[should_panic] +fn not_a_subslice() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b"012345"[0..4]; + + bytes.subslice(slice); +} + +#[test] +#[should_panic] +fn not_an_empty_subslice() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b""[0..0]; + + bytes.subslice(slice); +} + +#[test] +#[should_panic] +fn not_a_subslice_empty() { + let bytes = Bytes::from(&b""[..]); + let slice = &b""[0..0]; + + bytes.subslice(slice); +}