|  | @@ -4,6 +4,8 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  //! Sets for lazily storing ordered, non-overlapping ranges of integers.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +use std::cmp;
 | 
	
		
			
				|  |  | +use std::iter;
 | 
	
		
			
				|  |  |  use std::slice;
 | 
	
		
			
				|  |  |  use std::str::FromStr;
 | 
	
		
			
				|  |  |  use std::u32;
 | 
	
	
		
			
				|  | @@ -240,8 +242,8 @@ impl ProtoSet {
 | 
	
		
			
				|  |  |          false
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// Retain only the `Version`s in this `ProtoSet` for which the predicate
 | 
	
		
			
				|  |  | -    /// `F` returns `true`.
 | 
	
		
			
				|  |  | +    /// Returns all the `Version`s in `self` which are not also in the `other`
 | 
	
		
			
				|  |  | +    /// `ProtoSet`.
 | 
	
		
			
				|  |  |      ///
 | 
	
		
			
				|  |  |      /// # Examples
 | 
	
		
			
				|  |  |      ///
 | 
	
	
		
			
				|  | @@ -250,24 +252,45 @@ impl ProtoSet {
 | 
	
		
			
				|  |  |      /// use protover::protoset::ProtoSet;
 | 
	
		
			
				|  |  |      ///
 | 
	
		
			
				|  |  |      /// # fn do_test() -> Result<bool, ProtoverError> {
 | 
	
		
			
				|  |  | -    /// let mut protoset: ProtoSet = "1,3-5,9".parse()?;
 | 
	
		
			
				|  |  | +    /// let protoset: ProtoSet = "1,3-6,10-12,15-16".parse()?;
 | 
	
		
			
				|  |  | +    /// let other: ProtoSet = "2,5-7,9-11,14-20".parse()?;
 | 
	
		
			
				|  |  |      ///
 | 
	
		
			
				|  |  | -    /// // Keep only versions less than or equal to 8:
 | 
	
		
			
				|  |  | -    /// protoset.retain(|x| x <= &8);
 | 
	
		
			
				|  |  | +    /// let subset: ProtoSet = protoset.and_not_in(&other);
 | 
	
		
			
				|  |  |      ///
 | 
	
		
			
				|  |  | -    /// assert_eq!(protoset.expand(), vec![1, 3, 4, 5]);
 | 
	
		
			
				|  |  | +    /// assert_eq!(subset.expand(), vec![1, 3, 4, 12]);
 | 
	
		
			
				|  |  |      /// #
 | 
	
		
			
				|  |  |      /// # Ok(true)
 | 
	
		
			
				|  |  |      /// # }
 | 
	
		
			
				|  |  |      /// # fn main() { do_test(); }  // wrap the test so we can use the ? operator
 | 
	
		
			
				|  |  |      /// ```
 | 
	
		
			
				|  |  | -    // XXX we could probably do something more efficient here. —isis
 | 
	
		
			
				|  |  | -    pub fn retain<F>(&mut self, f: F)
 | 
	
		
			
				|  |  | -        where F: FnMut(&Version) -> bool
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        let mut expanded: Vec<Version> = self.clone().expand();
 | 
	
		
			
				|  |  | -        expanded.retain(f);
 | 
	
		
			
				|  |  | -        *self = expanded.into();
 | 
	
		
			
				|  |  | +    pub fn and_not_in(&self, other: &Self) -> Self {
 | 
	
		
			
				|  |  | +        if self.is_empty() || other.is_empty() {
 | 
	
		
			
				|  |  | +            return self.clone();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let pairs = self.iter().flat_map(|&(lo, hi)| {
 | 
	
		
			
				|  |  | +            let the_end = (hi + 1, hi + 1); // special case to mark the end of the range.
 | 
	
		
			
				|  |  | +            let excluded_ranges = other
 | 
	
		
			
				|  |  | +                .iter()
 | 
	
		
			
				|  |  | +                .cloned() // have to be owned tuples, to match iter::once(the_end).
 | 
	
		
			
				|  |  | +                .skip_while(move|&(_, hi2)| hi2 < lo) // skip the non-overlapping ranges.
 | 
	
		
			
				|  |  | +                .take_while(move|&(lo2, _)| lo2 <= hi) // take all the overlapping ones.
 | 
	
		
			
				|  |  | +                .chain(iter::once(the_end));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            let mut nextlo = lo;
 | 
	
		
			
				|  |  | +            excluded_ranges.filter_map(move |(excluded_lo, excluded_hi)| {
 | 
	
		
			
				|  |  | +                let pair = if nextlo < excluded_lo {
 | 
	
		
			
				|  |  | +                    Some((nextlo, excluded_lo - 1))
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    None
 | 
	
		
			
				|  |  | +                };
 | 
	
		
			
				|  |  | +                nextlo = cmp::min(excluded_hi, u32::MAX - 1) + 1;
 | 
	
		
			
				|  |  | +                pair
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let pairs = pairs.collect();
 | 
	
		
			
				|  |  | +        ProtoSet::is_ok(ProtoSet{ pairs }).expect("should be already sorted")
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |