Skip to content

Commit

Permalink
Add a subslice function for Bytes (#198) (#208)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
federicomenaquintero authored and carllerche committed Sep 2, 2018
1 parent ed244d3 commit 79f0559
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 @@ -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`
Expand Down
54 changes: 54 additions & 0 deletions tests/test_bytes.rs
Expand Up @@ -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);
}

0 comments on commit 79f0559

Please sign in to comment.