rosu_mods/
intersection.rs

1use std::{
2    cmp::{min, Ordering},
3    collections::{btree_map::Iter as TreeIter, btree_set::Iter as SetIter},
4};
5
6use crate::{
7    generated_mods::{GameMod, GameModIntermode},
8    order::GameModOrder,
9};
10
11pub(super) enum IntersectionInner<I, A> {
12    Stitch(Stitch<I>),
13    Answer(Option<A>),
14}
15
16impl<I, A> IntersectionInner<I, A> {
17    pub(super) const fn new_stitch(a: I, b: I) -> Self {
18        Self::Stitch(Stitch { a, b })
19    }
20}
21
22pub(super) struct Stitch<I> {
23    a: I,
24    b: I,
25}
26
27/// Iterator over [`GameMod`] references that appear in both given [`GameMods`].
28///
29/// Created by [`GameMods::intersection`].
30///
31/// [`GameMods`]: crate::GameMods
32/// [`GameMods::intersection`]: crate::GameMods::intersection
33// https://github.com/rust-lang/rust/blob/c1d3610ac1ddd1cd605479274047fd0a3f37d220/library/alloc/src/collections/btree/set.rs#L256
34pub struct GameModsIntersection<'m> {
35    pub(super) inner: IntersectionInner<TreeIter<'m, GameModOrder, GameMod>, &'m GameMod>,
36}
37
38impl<'m> Iterator for GameModsIntersection<'m> {
39    type Item = &'m GameMod;
40
41    fn next(&mut self) -> Option<Self::Item> {
42        match &mut self.inner {
43            IntersectionInner::Stitch(Stitch { a, b }) => {
44                let mut a_next = a.next()?;
45                let mut b_next = b.next()?;
46
47                loop {
48                    match a_next.0.cmp(b_next.0) {
49                        Ordering::Less => a_next = a.next()?,
50                        Ordering::Greater => b_next = b.next()?,
51                        Ordering::Equal => return Some(a_next.1),
52                    }
53                }
54            }
55            IntersectionInner::Answer(answer) => answer.take(),
56        }
57    }
58
59    fn size_hint(&self) -> (usize, Option<usize>) {
60        match &self.inner {
61            IntersectionInner::Stitch(Stitch { a, b }) => (0, Some(min(a.len(), b.len()))),
62            IntersectionInner::Answer(None) => (0, Some(0)),
63            IntersectionInner::Answer(Some(_)) => (1, Some(1)),
64        }
65    }
66
67    fn min(mut self) -> Option<Self::Item> {
68        self.next()
69    }
70}
71
72/// Iterator over [`GameModIntermode`]s that appear in both given [`GameModsIntermode`].
73///
74/// Created by [`GameModsIntermode::intersection`].
75///
76/// [`GameModsIntermode`]: crate::GameModsIntermode
77/// [`GameModsIntermode::intersection`]: crate::GameModsIntermode::intersection
78pub struct GameModsIntermodeIntersection<'m> {
79    pub(super) inner: IntersectionInner<SetIter<'m, GameModIntermode>, GameModIntermode>,
80}
81
82impl Iterator for GameModsIntermodeIntersection<'_> {
83    type Item = GameModIntermode;
84
85    fn next(&mut self) -> Option<Self::Item> {
86        match &mut self.inner {
87            IntersectionInner::Stitch(Stitch { a, b }) => {
88                let mut a_next = a.next()?;
89                let mut b_next = b.next()?;
90
91                loop {
92                    match a_next.cmp(b_next) {
93                        Ordering::Less => a_next = a.next()?,
94                        Ordering::Greater => b_next = b.next()?,
95                        Ordering::Equal => return Some(*a_next),
96                    }
97                }
98            }
99            IntersectionInner::Answer(answer) => answer.take(),
100        }
101    }
102
103    fn size_hint(&self) -> (usize, Option<usize>) {
104        match &self.inner {
105            IntersectionInner::Stitch(Stitch { a, b }) => (0, Some(min(a.len(), b.len()))),
106            IntersectionInner::Answer(None) => (0, Some(0)),
107            IntersectionInner::Answer(Some(_)) => (1, Some(1)),
108        }
109    }
110
111    fn min(mut self) -> Option<Self::Item> {
112        self.next()
113    }
114}