Skip to content

Commit

Permalink
Add a subslice function for Bytes (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
federicomenaquintero committed May 31, 2018
1 parent 8d5b46c commit afb8a32
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
40 changes: 40 additions & 0 deletions src/bytes.rs
Expand Up @@ -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`
Expand Down
54 changes: 54 additions & 0 deletions tests/test_bytes.rs
Expand Up @@ -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);
}

0 comments on commit afb8a32

Please sign in to comment.