@@ -5122,6 +5122,97 @@ pub trait Itertools: Iterator {
51225122 _ => Err ( sh) ,
51235123 }
51245124 }
5125+
5126+ /// Removes a prefix from the iterator, returning the rest.
5127+ ///
5128+ /// If `self` begins with all the items yielded by `prefix` (in order), this
5129+ /// returns `Ok` of the iterator advanced past that prefix. Otherwise it
5130+ /// returns `Err(StripPrefixError { .. })` exposing the partially-consumed
5131+ /// iterator, the remaining prefix, and the items that failed to match, so
5132+ /// callers can recover progress made before the mismatch.
5133+ ///
5134+ /// See [`strip_prefix_by`](Itertools::strip_prefix_by) for a variant
5135+ /// taking an explicit equality predicate.
5136+ ///
5137+ /// ```
5138+ /// use itertools::Itertools;
5139+ ///
5140+ /// let ok = (1..6).strip_prefix([1, 2]).map(Itertools::collect_vec).ok();
5141+ /// assert_eq!(ok, Some(vec![3, 4, 5]));
5142+ /// assert!((1..6).strip_prefix([1, 9]).is_err());
5143+ /// let empty = (1..6).strip_prefix(std::iter::empty::<i32>()).map(Itertools::collect_vec).ok();
5144+ /// assert_eq!(empty, Some(vec![1, 2, 3, 4, 5]));
5145+ /// ```
5146+ fn strip_prefix < Prefix > (
5147+ self ,
5148+ prefix : Prefix ,
5149+ ) -> Result < Self , StripPrefixError < Self , Prefix :: IntoIter , Self :: Item > >
5150+ where
5151+ Self : Sized ,
5152+ Prefix : IntoIterator ,
5153+ Self :: Item : PartialEq < Prefix :: Item > ,
5154+ {
5155+ self . strip_prefix_by ( prefix, |a, b| a == b)
5156+ }
5157+
5158+ /// Removes a prefix from the iterator using `eq` to compare items.
5159+ ///
5160+ /// If `self` begins with all the items yielded by `prefix` (in order, as
5161+ /// judged by `eq`), this returns `Ok` of the iterator advanced past that
5162+ /// prefix. Otherwise it returns `Err(StripPrefixError { .. })`, allowing
5163+ /// the prefix items to have a different type than `Self::Item`.
5164+ ///
5165+ /// ```
5166+ /// use itertools::Itertools;
5167+ ///
5168+ /// let path = ["home", "user", "file"];
5169+ /// let stripped = path.iter().strip_prefix_by(["home", "user"], |a, b| **a == *b);
5170+ /// assert_eq!(stripped.map(Itertools::collect_vec).ok(), Some(vec![&"file"]));
5171+ /// ```
5172+ fn strip_prefix_by < Prefix , F > (
5173+ mut self ,
5174+ prefix : Prefix ,
5175+ mut eq : F ,
5176+ ) -> Result < Self , StripPrefixError < Self , Prefix :: IntoIter , Self :: Item > >
5177+ where
5178+ Self : Sized ,
5179+ Prefix : IntoIterator ,
5180+ F : FnMut ( & Self :: Item , & Prefix :: Item ) -> bool ,
5181+ {
5182+ let mut prefix = prefix. into_iter ( ) ;
5183+ while let Some ( wanted) = prefix. next ( ) {
5184+ match self . next ( ) {
5185+ Some ( got) if eq ( & got, & wanted) => continue ,
5186+ got => {
5187+ return Err ( StripPrefixError {
5188+ iterator : self ,
5189+ prefix,
5190+ mismatch : ( got, wanted) ,
5191+ } ) ;
5192+ }
5193+ }
5194+ }
5195+ Ok ( self )
5196+ }
5197+ }
5198+
5199+ /// The error returned by [`Itertools::strip_prefix`] and
5200+ /// [`Itertools::strip_prefix_by`] when the iterator does not start with the
5201+ /// requested prefix.
5202+ ///
5203+ /// All fields are public so callers can recover the partially-consumed
5204+ /// iterators and the mismatched items.
5205+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
5206+ pub struct StripPrefixError < I , Prefix : Iterator , T > {
5207+ /// The remainder of the original iterator, advanced past the matched
5208+ /// prefix items but stopped at the position of the mismatch.
5209+ pub iterator : I ,
5210+ /// The remainder of the prefix iterator, starting just after the prefix
5211+ /// item that failed to match.
5212+ pub prefix : Prefix ,
5213+ /// The pair of items that failed to compare equal. The first element is
5214+ /// `None` if `iterator` was exhausted before the prefix was fully matched.
5215+ pub mismatch : ( Option < T > , Prefix :: Item ) ,
51255216}
51265217
51275218impl < T > Itertools for T where T : Iterator + ?Sized { }
0 commit comments