Skip to content

Commit

Permalink
Make StreamOnce for &'a [T] require Clone rather than Copy.
Browse files Browse the repository at this point in the history
Clone is a super-type of Copy, so everything that implements Copy
already implements Clone.  Therefore, this is strictly more general.
In addition, .clone() on things that implement Copy should be
inlined (to `return *self`) and essentially zero cost.  And per
Marwes#74 (comment),
.clone() already be fast in order for parsing to be fast, so the
performance assumptions in the non-Copy case should be similar.
  • Loading branch information
ncalexan committed Jan 6, 2017
1 parent f412966 commit fda4038
Showing 1 changed file with 17 additions and 4 deletions.
21 changes: 17 additions & 4 deletions src/primitives.rs
Expand Up @@ -711,7 +711,7 @@ impl<'a, T> Range for &'a [T] {
}

impl<'a, T> RangeStream for &'a [T]
where T: Copy + PartialEq
where T: Clone + PartialEq
{
#[inline]
fn uncons_range(&mut self, size: usize) -> Result<&'a [T], Error<T, &'a [T]>> {
Expand All @@ -728,7 +728,7 @@ impl<'a, T> RangeStream for &'a [T]
where F: FnMut(Self::Item) -> bool
{
let len = self.iter()
.take_while(|c| f(**c))
.take_while(|c| f((**c).clone()))
.count();
let (result, remaining) = self.split_at(len);
*self = remaining;
Expand Down Expand Up @@ -760,7 +760,7 @@ impl<'a> StreamOnce for &'a str {
}

impl<'a, T> StreamOnce for &'a [T]
where T: Copy + PartialEq
where T: Clone + PartialEq
{
type Item = T;
type Range = &'a [T];
Expand All @@ -771,7 +771,7 @@ impl<'a, T> StreamOnce for &'a [T]
match self.split_first() {
Some((first, rest)) => {
*self = rest;
Ok(*first)
Ok(first.clone())
}
None => Err(Error::end_of_input()),
}
Expand Down Expand Up @@ -1711,4 +1711,17 @@ mod tests {
let s: &[u8] = &[];
assert_eq!(SliceStream(s).uncons_range(0), Ok(&[][..]));
}

#[derive(Clone, PartialEq, Debug)]
struct CloneOnly {
s: String,
}

#[test]
fn parse_clone_but_not_copy() {
// This verifies we can parse slice references with an item type that is Clone but not Copy.
let input = &[CloneOnly { s: "x".to_string() }, CloneOnly { s: "y".to_string() }][..];
let result = ::range::take_while(|c: CloneOnly| c.s == "x".to_string()).parse(input);
assert_eq!(result, Ok((&[CloneOnly { s: "x".to_string() }][..], &[CloneOnly { s: "y".to_string() }][..])));
}
}

0 comments on commit fda4038

Please sign in to comment.