iter_set/
lib.rs

1#![no_std]
2#![deny(missing_debug_implementations, missing_copy_implementations)]
3#![doc(html_root_url = "https://docs.rs/log/2.0.2")]
4
5//! This crate provides set operations on sorted, deduplicated iterators. Unless otherwise
6//! specified, all iterator parameters in this crate should yield elements in ascending order with
7//! consecutive repeated elements removed. If this is upheld, then all iterators returned by this
8//! crate will share those properties.
9
10#[cfg(test)]
11extern crate std;
12
13mod put_back;
14#[cfg(test)]
15mod tests;
16
17use core::cmp::{self, Ordering};
18use core::fmt::{self, Debug};
19
20use self::put_back::PutBack;
21
22/// Compare two sets represented by sorted, deduplicated iterators.
23///
24/// The return value represents a partial ordering based on set inclusion. If the iterators
25/// are equal, then `Some(Equal)` is returned. If `a` is a subset of `b` then `Some(Less)`
26/// is returned. If `a` is a superset of `b` then `Some(Greater)` is returned. Otherwise,
27/// `None` is returned. If `a` and `b` are not sorted or contain duplicate values, the return
28/// value is unspecified.
29///
30/// Time complexity: `O(a.len() + b.len())`.
31///
32/// # Examples
33///
34/// ```
35/// use std::cmp::Ordering::{Equal, Greater, Less};
36/// use iter_set::cmp;
37///
38/// let a = [1, 2, 3];
39/// let b = [2, 3];
40/// let c = [2, 3, 4];
41///
42/// assert_eq!(cmp(&a, &b), Some(Greater));
43/// assert_eq!(cmp(&b, &b), Some(Equal));
44/// assert_eq!(cmp(&b, &c), Some(Less));
45/// assert_eq!(cmp(&a, &c), None);
46/// ```
47pub fn cmp<T, L, R>(a: L, b: R) -> Option<Ordering>
48where
49    T: Ord,
50    L: IntoIterator<Item = T>,
51    R: IntoIterator<Item = T>,
52{
53    classify(a, b).try_fold(Ordering::Equal, cmp_fold)
54}
55
56/// Compare two sets represented by sorted, deduplicated iterators, using a key extraction function.
57///
58/// See [`cmp()`].
59///
60/// # Examples
61///
62/// ```
63/// use std::cmp::Ordering::{Equal, Greater, Less};
64/// use iter_set::cmp_by_key;
65///
66/// let a = [(1, "a"), (2, "b"), (3, "c")];
67/// let b = [(2, "d"), (3, "a")];
68/// let c = [(2, "b"), (3, "c"), (4, "d")];
69///
70/// assert_eq!(cmp_by_key(&a, &b, |&(key, _)| key), Some(Greater));
71/// assert_eq!(cmp_by_key(&b, &b, |&(key, _)| key), Some(Equal));
72/// assert_eq!(cmp_by_key(&b, &c, |&(key, _)| key), Some(Less));
73/// assert_eq!(cmp_by_key(&a, &c, |&(key, _)| key), None);
74/// ```
75pub fn cmp_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> Option<Ordering>
76where
77    L: IntoIterator<Item = T>,
78    R: IntoIterator<Item = T>,
79    K: Ord,
80    F: FnMut(&T) -> K,
81{
82    classify_by_key(a, b, key).try_fold(Ordering::Equal, cmp_fold)
83}
84
85/// Compare two sets represented by sorted, deduplicated iterators, using a comparator function.
86///
87/// See [`cmp()`].
88///
89/// # Examples
90///
91/// Using a custom comparator to reverse the ordering
92///
93/// ```
94/// use std::cmp::Ordering::{Equal, Greater, Less};
95/// use iter_set::cmp_by;
96///
97/// let a = [3, 2, 1];
98/// let b = [3, 2];
99/// let c = [4, 3, 2];
100///
101/// assert_eq!(cmp_by(&a, &b, |l, r| Ord::cmp(r, l)), Some(Greater));
102/// assert_eq!(cmp_by(&b, &b, |l, r| Ord::cmp(r, l)), Some(Equal));
103/// assert_eq!(cmp_by(&b, &c, |l, r| Ord::cmp(r, l)), Some(Less));
104/// assert_eq!(cmp_by(&a, &c, |l, r| Ord::cmp(r, l)), None);
105/// ```
106pub fn cmp_by<T, L, R, F>(a: L, b: R, cmp: F) -> Option<Ordering>
107where
108    L: IntoIterator<Item = T>,
109    R: IntoIterator<Item = T>,
110    F: FnMut(&mut T, &mut T) -> Ordering,
111{
112    classify_by(a, b, cmp).try_fold(Ordering::Equal, cmp_fold)
113}
114
115fn cmp_fold<T>(init: Ordering, next: Inclusion<T>) -> Option<Ordering> {
116    use Ordering::*;
117
118    match (init, next.ordering()) {
119        (Less, Greater) | (Greater, Less) => None,
120        (Equal, x) | (x, Equal) => Some(x),
121        (Greater, Greater) => Some(Greater),
122        (Less, Less) => Some(Less),
123    }
124}
125
126/// Take the union of two sets represented by sorted, deduplicated iterators.
127///
128/// If an element is in both iterators, then only the one from `a` is yielded.
129/// This behaviour can be overridden by using [`union_by()`].
130///
131/// Time complexity: `O(a.len() + b.len())`.
132///
133/// # Examples
134///
135/// ```
136/// use iter_set::union;
137///
138/// let a = [1, 2];
139/// let b = [2, 3];
140///
141/// assert!(union(&a, &b).eq(&[1, 2, 3]));
142/// ```
143pub fn union<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
144where
145    T: Ord,
146    L: IntoIterator<Item = T>,
147    R: IntoIterator<Item = T>,
148{
149    classify(a, b).map(Inclusion::union)
150}
151
152/// Take the union of two sets represented by sorted, deduplicated iterators, using a comparator
153/// function.
154///
155/// Note that since this passes elements to the comparator function as `&mut T`, you can swap them
156/// to override the default behaviour of returning duplicate elements from `a`.
157///
158/// See [`union()`].
159///
160/// # Examples
161///
162/// Using the comparator function to perform a 'deep union'
163///
164/// ```
165/// use std::cmp::Ordering::{self, Equal, Greater, Less};
166/// use iter_set::union_by;
167///
168/// #[derive(Debug, Eq, PartialEq)]
169/// enum Foo {
170///     Zero,
171///     Some(Vec<u32>),
172/// }
173///
174/// fn combine(l: &mut Foo, r: &mut Foo) -> Ordering {
175///     match (l, r) {
176///         (Foo::Zero, Foo::Zero) => Equal,
177///         (Foo::Zero, Foo::Some(_)) => Less,
178///         (Foo::Some(_), Foo::Zero) => Greater,
179///         (Foo::Some(l), Foo::Some(r)) => {
180///             l.append(r);
181///             Equal
182///         }
183///     }
184/// }
185///
186/// let lhs = vec![Foo::Zero, Foo::Some(vec![1, 2])];
187/// let rhs = vec![Foo::Some(vec![3])];
188///
189/// let union: Vec<_> = union_by(lhs, rhs, combine).collect();
190/// assert_eq!(union, vec![Foo::Zero, Foo::Some(vec![1, 2, 3])]);
191/// ```
192pub fn union_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
193where
194    L: IntoIterator<Item = T>,
195    R: IntoIterator<Item = T>,
196    F: FnMut(&mut T, &mut T) -> Ordering,
197{
198    classify_by(a, b, cmp).map(Inclusion::union)
199}
200
201/// Take the union of two sets represented by sorted, deduplicated iterators, using a key extraction
202/// function.
203///
204/// See [`union()`].
205///
206/// # Examples
207///
208/// ```
209/// use iter_set::union_by_key;
210///
211/// let a = [(1, "a"), (2, "a")];
212/// let b = [(2, "b"), (3, "b")];
213///
214/// assert!(union_by_key(&a, &b, |&(key, _)| key).eq(&[(1, "a"), (2, "a"), (3, "b")]));
215/// ```
216pub fn union_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
217where
218    L: IntoIterator<Item = T>,
219    R: IntoIterator<Item = T>,
220    K: Ord,
221    F: FnMut(&T) -> K,
222{
223    classify_by_key(a, b, key).map(Inclusion::union)
224}
225
226/// Take the intersection of two sets represented by sorted, deduplicated iterators.
227///
228/// The elements returned will all be from `a`. This behaviour can be overridden by
229/// using [`intersection_by()`].
230///
231/// Time complexity: `O(a.len() + b.len())`.
232///
233/// # Examples
234///
235/// ```
236/// use iter_set::intersection;
237///
238/// let a = [1, 2];
239/// let b = [2, 3];
240///
241/// assert!(intersection(&a, &b).eq(&[2]));
242/// ```
243pub fn intersection<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
244where
245    T: Ord,
246    L: IntoIterator<Item = T>,
247    R: IntoIterator<Item = T>,
248{
249    classify(a, b)
250        .with_size_hint(intersection_size_hint)
251        .filter_map(Inclusion::intersection)
252}
253
254/// Take the intersection of two sets represented by sorted, deduplicated iterators, using a
255/// comparator function.
256///
257/// Note that since this passes elements to the comparator function as `&mut T`, you can swap them
258/// to override the default behaviour of returning duplicate elements from `a`.
259///
260/// See [`intersection()`].
261///
262/// # Examples
263///
264/// Using the comparator function to choose which iterator to take from.
265///
266/// ```
267/// use std::cmp::Ordering::{self, Equal};
268/// use std::mem::swap;
269/// use iter_set::intersection_by;
270///
271/// let mut a = [(1, vec![2]), (2, vec![])];
272/// let mut b = [(2, vec![1]), (3, vec![])];
273///
274/// fn compare(l: &mut (u32, Vec<i32>), r: &mut (u32, Vec<i32>)) -> Ordering {
275///     match Ord::cmp(&l.0, &r.0) {
276///        Equal => {
277///            if r.1.len() > l.1.len() {
278///                swap(r, l);
279///            }
280///            Equal
281///        }
282///        neq => neq,
283///     }
284/// }
285///
286/// assert!(intersection_by(&mut a, &mut b, |l, r| compare(*l, *r)).eq(&[(2, vec![1])]));
287/// ```
288pub fn intersection_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
289where
290    L: IntoIterator<Item = T>,
291    R: IntoIterator<Item = T>,
292    F: FnMut(&mut T, &mut T) -> Ordering,
293{
294    classify_by(a, b, cmp)
295        .with_size_hint(|iter| intersection_size_hint(&iter.inner))
296        .filter_map(Inclusion::intersection)
297}
298
299/// Take the intersection of two sets represented by sorted, deduplicated iterators, using a key
300/// extraction function.
301///
302/// See [`intersection()`].
303///
304/// # Examples
305///
306/// ```
307/// use iter_set::intersection_by_key;
308///
309/// let a = [(1, "a"), (2, "a")];
310/// let b = [(2, "b"), (3, "b")];
311///
312/// assert!(intersection_by_key(&a, &b, |&(key, _)| key).eq(&[(2, "a")]));
313/// ```
314pub fn intersection_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
315where
316    L: IntoIterator<Item = T>,
317    R: IntoIterator<Item = T>,
318    K: Ord,
319    F: FnMut(&T) -> K,
320{
321    classify_by_key(a, b, key)
322        .with_size_hint(|iter| intersection_size_hint(&iter.inner))
323        .filter_map(Inclusion::intersection)
324}
325
326/// Take the difference of two sets (elements in `a` but not in `b`) represented by sorted,
327/// deduplicated iterators.
328///
329/// Time complexity: `O(a.len() + b.len())`.
330///
331/// # Examples
332///
333/// ```
334/// use iter_set::difference;
335///
336/// let a = [1, 2];
337/// let b = [2, 3];
338///
339/// assert!(difference(&a, &b).eq(&[1]));
340/// ```
341pub fn difference<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
342where
343    T: Ord,
344    L: IntoIterator<Item = T>,
345    R: IntoIterator<Item = T>,
346{
347    classify(a, b)
348        .with_size_hint(difference_size_hint)
349        .filter_map(Inclusion::difference)
350}
351
352/// Take the difference of two sets represented by sorted, deduplicated iterators, using
353/// a comparator function.
354///
355/// See [`difference()`].
356pub fn difference_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
357where
358    L: IntoIterator<Item = T>,
359    R: IntoIterator<Item = T>,
360    F: FnMut(&mut T, &mut T) -> Ordering,
361{
362    classify_by(a, b, cmp)
363        .with_size_hint(|iter| difference_size_hint(&iter.inner))
364        .filter_map(Inclusion::difference)
365}
366
367/// Take the difference of two sets represented by sorted, deduplicated iterators, using a key
368/// extraction function.
369///
370/// See [`difference()`].
371pub fn difference_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
372where
373    L: IntoIterator<Item = T>,
374    R: IntoIterator<Item = T>,
375    K: Ord,
376    F: FnMut(&T) -> K,
377{
378    classify_by_key(a, b, key)
379        .with_size_hint(|iter| difference_size_hint(&iter.inner))
380        .filter_map(Inclusion::difference)
381}
382
383/// Take the symmetric_difference of two sets represented by sorted, deduplicated iterators.
384///
385/// Time complexity: `O(a.len() + b.len())`.
386///
387/// # Examples
388///
389/// ```
390/// use iter_set::symmetric_difference;
391///
392/// let a = [1, 2];
393/// let b = [2, 3];
394///
395/// assert!(symmetric_difference(&a, &b).eq(&[1, 3]));
396/// ```
397pub fn symmetric_difference<T, L, R>(a: L, b: R) -> impl Iterator<Item = T>
398where
399    T: Ord,
400    L: IntoIterator<Item = T>,
401    R: IntoIterator<Item = T>,
402{
403    classify(a, b).filter_map(Inclusion::symmetric_difference)
404}
405
406/// Take the symmetric_difference of two sets represented by sorted, deduplicated iterators,
407/// using a comparator function.
408///
409/// See [`symmetric_difference()`].
410pub fn symmetric_difference_by<T, L, R, F>(a: L, b: R, cmp: F) -> impl Iterator<Item = T>
411where
412    L: IntoIterator<Item = T>,
413    R: IntoIterator<Item = T>,
414    F: FnMut(&mut T, &mut T) -> Ordering,
415{
416    classify_by(a, b, cmp).filter_map(Inclusion::symmetric_difference)
417}
418
419/// Take the symmetric_difference of two sets represented by sorted, deduplicated iterators, using a
420/// key extraction function.
421///
422/// See [`symmetric_difference()`].
423pub fn symmetric_difference_by_key<T, L, R, K, F>(a: L, b: R, key: F) -> impl Iterator<Item = T>
424where
425    L: IntoIterator<Item = T>,
426    R: IntoIterator<Item = T>,
427    K: Ord,
428    F: FnMut(&T) -> K,
429{
430    classify_by_key(a, b, key).filter_map(Inclusion::symmetric_difference)
431}
432
433/// Interleave two sorted, deduplicated iterators in sorted order and classify each element according
434/// to its source.
435///
436/// # Examples
437///
438/// ```
439/// use iter_set::{classify, Inclusion};
440///
441/// let a = [1, 2];
442/// let b = [2, 3];
443///
444/// assert!(classify(&a, &b).eq(vec![Inclusion::Left(&1), Inclusion::Both(&2, &2), Inclusion::Right(&3)]));
445/// ```
446pub fn classify<T, L, R>(a: L, b: R) -> Classify<L::IntoIter, R::IntoIter>
447where
448    T: Ord,
449    L: IntoIterator<Item = T>,
450    R: IntoIterator<Item = T>,
451{
452    Classify::new(a, b)
453}
454
455/// Interleave two sorted, deduplicated iterators in sorted order and classify each element according
456/// to its source, using a comparator function.
457///
458/// See [`classify()`].
459pub fn classify_by<T, L, R, F>(a: L, b: R, cmp: F) -> ClassifyBy<L::IntoIter, R::IntoIter, F>
460where
461    L: IntoIterator<Item = T>,
462    R: IntoIterator<Item = T>,
463    F: FnMut(&mut T, &mut T) -> Ordering,
464{
465    ClassifyBy {
466        inner: Classify::new(a, b),
467        cmp,
468    }
469}
470
471/// Interleave two sorted, deduplicated iterators in sorted order and classify each element according
472/// to its source, using a key extraction function.
473///
474/// See [`classify()`].
475pub fn classify_by_key<T, L, R, K, F>(
476    a: L,
477    b: R,
478    key: F,
479) -> ClassifyByKey<L::IntoIter, R::IntoIter, F>
480where
481    L: IntoIterator<Item = T>,
482    R: IntoIterator<Item = T>,
483    K: Ord,
484    F: FnMut(&T) -> K,
485{
486    ClassifyByKey {
487        inner: Classify::new(a, b),
488        key,
489    }
490}
491
492/// An iterator that interleaves two sorted, deduplicated iterators in sorted order and classifies
493/// each element according to its source.
494///
495/// This `struct` is created by the [`classify()`] function. See its documentation
496/// for more.
497pub struct Classify<L, R>
498where
499    L: Iterator,
500    R: Iterator,
501{
502    lhs: PutBack<L>,
503    rhs: PutBack<R>,
504}
505
506impl<T, L, R> Classify<L, R>
507where
508    L: Iterator<Item = T>,
509    R: Iterator<Item = T>,
510{
511    fn new(
512        lhs: impl IntoIterator<IntoIter = L, Item = T>,
513        rhs: impl IntoIterator<IntoIter = R, Item = T>,
514    ) -> Self {
515        Classify {
516            lhs: PutBack::new(lhs.into_iter()),
517            rhs: PutBack::new(rhs.into_iter()),
518        }
519    }
520
521    fn next_by<F>(&mut self, mut cmp: F) -> Option<Inclusion<T>>
522    where
523        F: FnMut(&mut T, &mut T) -> Ordering,
524    {
525        match (self.lhs.next(), self.rhs.next()) {
526            (Some(mut l), Some(mut r)) => match cmp(&mut l, &mut r) {
527                Ordering::Less => {
528                    self.rhs.put_back(r);
529                    Some(Inclusion::Left(l))
530                }
531                Ordering::Equal => Some(Inclusion::Both(l, r)),
532                Ordering::Greater => {
533                    self.lhs.put_back(l);
534                    Some(Inclusion::Right(r))
535                }
536            },
537            (Some(l), None) => Some(Inclusion::Left(l)),
538            (None, Some(r)) => Some(Inclusion::Right(r)),
539            (None, None) => None,
540        }
541    }
542
543    fn size_hint(&self) -> (usize, Option<usize>) {
544        let (lmin, lmax) = self.lhs.size_hint();
545        let (rmin, rmax) = self.rhs.size_hint();
546        let min = cmp::max(lmin, rmin);
547        let max = match (lmax, rmax) {
548            (Some(lmax), Some(rmax)) => lmax.checked_add(rmax),
549            _ => None,
550        };
551        (min, max)
552    }
553}
554
555/// The sets an element is included in.
556#[derive(Debug, Copy, Clone, PartialEq, Eq)]
557pub enum Inclusion<T> {
558    // The element is in the left set only.
559    Left(T),
560    // The element is in both sets.
561    Both(T, T),
562    // The element is in the right set only.
563    Right(T),
564}
565
566impl<T> Inclusion<T> {
567    /// Return the element, whichever set it is in. If it is in both sets, the left element is returned.
568    pub fn union(self) -> T {
569        match self {
570            Inclusion::Left(l) => l,
571            Inclusion::Both(l, _) => l,
572            Inclusion::Right(r) => r,
573        }
574    }
575
576    /// Return the element if it is in both sets. The left element is returned.
577    pub fn intersection(self) -> Option<T> {
578        match self {
579            Inclusion::Left(_) | Inclusion::Right(_) => None,
580            Inclusion::Both(l, _) => Some(l),
581        }
582    }
583
584    /// Return the element if it is in the left set.
585    pub fn difference(self) -> Option<T> {
586        match self {
587            Inclusion::Left(l) => Some(l),
588            Inclusion::Both(_, _) | Inclusion::Right(_) => None,
589        }
590    }
591
592    /// Return the element if it is in exactly one set.
593    pub fn symmetric_difference(self) -> Option<T> {
594        match self {
595            Inclusion::Left(l) => Some(l),
596            Inclusion::Both(_, _) => None,
597            Inclusion::Right(r) => Some(r),
598        }
599    }
600
601    /// Return an [`Ordering`] based on where the element is from.
602    /// * `Ordering::Less`: from the right set.
603    /// * `Ordering::Equal`: from both sets
604    /// * `Ordering::Greater`: from the left set.
605    pub fn ordering(&self) -> Ordering {
606        match self {
607            Inclusion::Left(_) => Ordering::Greater,
608            Inclusion::Both(_, _) => Ordering::Equal,
609            Inclusion::Right(_) => Ordering::Less,
610        }
611    }
612}
613
614impl<T, L, R> Iterator for Classify<L, R>
615where
616    T: Ord,
617    L: Iterator<Item = T>,
618    R: Iterator<Item = T>,
619{
620    type Item = Inclusion<T>;
621
622    fn next(&mut self) -> Option<Self::Item> {
623        self.next_by(|l, r| Ord::cmp(l, r))
624    }
625
626    fn size_hint(&self) -> (usize, Option<usize>) {
627        self.size_hint()
628    }
629}
630
631/// An iterator that interleaves two sorted, deduplicated iterators in sorted order and classifies
632/// each element according to its source, using a comparator function.
633///
634/// This `struct` is created by the [`classify_by()`] function. See its
635/// documentation for more.
636pub struct ClassifyBy<L, R, F>
637where
638    L: Iterator,
639    R: Iterator,
640{
641    inner: Classify<L, R>,
642    cmp: F,
643}
644
645impl<T, L, R, F> Iterator for ClassifyBy<L, R, F>
646where
647    L: Iterator<Item = T>,
648    R: Iterator<Item = T>,
649    F: FnMut(&mut T, &mut T) -> Ordering,
650{
651    type Item = Inclusion<T>;
652
653    fn next(&mut self) -> Option<Self::Item> {
654        self.inner.next_by(&mut self.cmp)
655    }
656
657    fn size_hint(&self) -> (usize, Option<usize>) {
658        self.inner.size_hint()
659    }
660}
661
662/// An iterator that interleaves two sorted, deduplicated iterators in sorted order and classifies
663/// each element according to its source, using a key extraction function.
664///
665/// This `struct` is created by the [`classify_by_key()`] function. See its
666/// documentation for more.
667pub struct ClassifyByKey<L, R, F>
668where
669    L: Iterator,
670    R: Iterator,
671{
672    inner: Classify<L, R>,
673    key: F,
674}
675
676impl<T, L, R, K, F> Iterator for ClassifyByKey<L, R, F>
677where
678    L: Iterator<Item = T>,
679    R: Iterator<Item = T>,
680    K: Ord,
681    F: FnMut(&T) -> K,
682{
683    type Item = Inclusion<T>;
684
685    fn next(&mut self) -> Option<Self::Item> {
686        let key = &mut self.key;
687        self.inner.next_by(|l, r| Ord::cmp(&key(l), &key(r)))
688    }
689
690    fn size_hint(&self) -> (usize, Option<usize>) {
691        self.inner.size_hint()
692    }
693}
694
695impl<L, R> Debug for Classify<L, R>
696where
697    L: Debug + Iterator,
698    R: Debug + Iterator,
699{
700    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
701        f.debug_struct("Classify")
702            .field("lhs", &self.lhs)
703            .field("rhs", &self.rhs)
704            .finish()
705    }
706}
707
708impl<L, R, F> Debug for ClassifyBy<L, R, F>
709where
710    L: Debug + Iterator,
711    R: Debug + Iterator,
712{
713    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
714        f.debug_struct("ClassifyBy")
715            .field("lhs", &self.inner.lhs)
716            .field("rhs", &self.inner.rhs)
717            .finish()
718    }
719}
720
721impl<L, R, F> Debug for ClassifyByKey<L, R, F>
722where
723    L: Debug + Iterator,
724    R: Debug + Iterator,
725{
726    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
727        f.debug_struct("ClassifyByKey")
728            .field("lhs", &self.inner.lhs)
729            .field("rhs", &self.inner.rhs)
730            .finish()
731    }
732}
733
734struct SizeHintIterator<I, F> {
735    iter: I,
736    f: F,
737}
738
739impl<I, F> Iterator for SizeHintIterator<I, F>
740where
741    I: Iterator,
742    F: Fn(&I) -> (usize, Option<usize>),
743{
744    type Item = I::Item;
745
746    fn next(&mut self) -> Option<Self::Item> {
747        self.iter.next()
748    }
749
750    fn size_hint(&self) -> (usize, Option<usize>) {
751        (self.f)(&self.iter)
752    }
753}
754
755trait WithSizeHint
756where
757    Self: Sized + Iterator,
758{
759    fn with_size_hint<F>(self, f: F) -> SizeHintIterator<Self, F>
760    where
761        F: Fn(&Self) -> (usize, Option<usize>),
762    {
763        SizeHintIterator { iter: self, f }
764    }
765}
766
767impl<I> WithSizeHint for I
768where
769    Self: Sized,
770    I: Iterator,
771{
772}
773
774fn intersection_size_hint<L, R>(classify: &Classify<L, R>) -> (usize, Option<usize>)
775where
776    L: Iterator,
777    R: Iterator,
778{
779    let (_, lmax) = classify.lhs.size_hint();
780    let (_, rmax) = classify.rhs.size_hint();
781
782    let max = match (lmax, rmax) {
783        (Some(l), Some(r)) => Some(l.min(r)),
784        (_, _) => None,
785    };
786
787    (0, max)
788}
789
790fn difference_size_hint<L, R>(classify: &Classify<L, R>) -> (usize, Option<usize>)
791where
792    L: Iterator,
793    R: Iterator,
794{
795    let (_, lmax) = classify.lhs.size_hint();
796    (0, lmax)
797}