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}