empty_fallback_chain/
lib.rs

1//! [core-iter-chain]: `core::iter::Chain`
2//! [iterator-ext-method]: `IteratorExt::empty_fallback_chain`
3#![doc = include_str!("../README.md")]
4#![cfg_attr(not(test), no_std)]
5
6// TODO: in next major version, change the [`empty_fallback_chain`], [`maybe_empty_fallback_chain`],
7// and [`pre_empty_fallback_chain`] functions to use IntoIterator and make them non-const, to align
8// them with how std does free functions and make them not just glorified invokers of the constructor.
9
10/// Construct an [`EmptyFallbackChain`] iterator. See [`IteratorExt::empty_fallback_chain`] for
11/// more information.
12#[inline]
13pub fn empty_fallback_chain<A: IntoIterator, B: IntoIterator<Item = A::Item>>(
14    a: A,
15    b: B,
16) -> EmptyFallbackChain<A::IntoIter, B::IntoIter> {
17    EmptyFallbackChain::new(a.into_iter(), b.into_iter())
18}
19
20/// Construct an [`EmptyFallbackChain`] iterator with the second one optionally "pre-emptively made
21/// empty"
22///
23/// See [`IteratorExt::maybe_empty_fallback_chain`] for more information.
24#[inline]
25pub fn maybe_empty_fallback_chain<A: IntoIterator, B: IntoIterator<Item = A::Item>>(
26    a: A,
27    b: Option<B>,
28) -> EmptyFallbackChain<A::IntoIter, B::IntoIter> {
29    EmptyFallbackChain::new_with_pre_empty(Some(a.into_iter()), b.map(IntoIterator::into_iter))
30}
31
32/// Create an [`EmptyFallbackChain`] with (optionally) one or more of the iterators set to "empty"
33/// pre-emptively, by providing it as [`None`].
34///
35/// This is useful when creating conditional combinators as it prevents nested iterator type explosion, and the
36/// associated indirection.
37///
38/// See also: [`IteratorExt::maybe_empty_fallback_chain`]
39///
40/// ```rust
41/// use empty_fallback_chain as efc;
42///
43/// let o = efc::pre_empty_fallback_chain::<core::iter::Empty<usize>, _>(
44///     None,
45///     Some([3, 4, 5].into_iter())
46/// ).collect::<Vec<usize>>();
47/// assert_eq!(o, vec![3, 4, 5]);
48/// ```
49#[inline]
50pub fn pre_empty_fallback_chain<A: IntoIterator, B: IntoIterator<Item = A::Item>>(
51    a: Option<A>,
52    b: Option<B>,
53) -> EmptyFallbackChain<A::IntoIter, B::IntoIter> {
54    EmptyFallbackChain::new_with_pre_empty(
55        a.map(IntoIterator::into_iter),
56        b.map(IntoIterator::into_iter),
57    )
58}
59
60/// An iterator that links two iterators together, in a chain, if the first produces nothing.
61///
62/// This iterator is double ended - like [`core::iter::Chain`] - and behaves symmetrically in
63/// reverse - once you call either [`Iterator::next`] or [`DoubleEndedIterator::next_back`], the first
64/// iterator *in that direction* determines if the second iterator *in that direction* is
65/// preserved.
66///
67/// For more information, see [`IteratorExt::empty_fallback_chain`]
68#[derive(Debug, Clone)]
69#[must_use = "iterators are lazy and do nothing unless consumed"]
70pub struct EmptyFallbackChain<A, B> {
71    // This is like in `core::iter::Chain` - the Option values act to fuse the iterators.
72    //
73    // Destroying the second iterator is acheived by setting it to `None` in the and_then_or_clear
74    // function (mirroring the internal function of the same name inside rust stdlib).
75    //
76    // This also works (in reverse) for the double-ended case, with flipped behaviour
77    a: Option<A>,
78    b: Option<B>,
79}
80
81impl<A, B> EmptyFallbackChain<A, B> {
82    /// Construct a new [`EmptyFallbackChain`] from the two iterators.
83    #[inline]
84    pub const fn new(a: A, b: B) -> EmptyFallbackChain<A, B> {
85        Self {
86            a: Some(a),
87            b: Some(b),
88        }
89    }
90
91    /// Allow creating a new [`EmptyFallbackChain`] while implicitly allowing one or both of the
92    /// iterators to be pre-emptively considered "empty" by setting them to [`None`]. See
93    /// [`pre_empty_fallback_chain`] for more information.
94    #[inline]
95    pub const fn new_with_pre_empty(a: Option<A>, b: Option<B>) -> EmptyFallbackChain<A, B> {
96        Self { a, b }
97    }
98}
99
100/// Implementation of [`Iterator`] - takes significant work and code from [`core::iter::Chain`]'s
101/// implementation.
102impl<A, B> Iterator for EmptyFallbackChain<A, B>
103where
104    A: Iterator,
105    B: Iterator<Item = A::Item>,
106{
107    type Item = A::Item;
108
109    #[inline]
110    fn next(&mut self) -> Option<Self::Item> {
111        and_then_or_clear(&mut self.a, Iterator::next, || self.b = None)
112            .or_else(|| self.b.as_mut()?.next())
113    }
114
115    #[inline]
116    fn count(self) -> usize
117    where
118        Self: Sized,
119    {
120        let a_count = match self.a {
121            Some(a) => a.count(),
122            None => 0,
123        };
124        // `self.b` would get dumped anyway, and this function is consuming.
125        //
126        if a_count != 0 {
127            return a_count;
128        }
129        // If `self.a` was totally consumed but hadn't yet returned `None`, then on the
130        // first call, `self.b` would have been destroyed anyway, so continuing when a.count()
131        // is zero is still fine - there can't be an issue where:
132        // * `a` has cnt zero
133        // * `a` was not an empty iterator
134        // * `b` was not None
135        match self.b {
136            Some(b) => b.count(),
137            None => 0,
138        }
139    }
140
141    /*
142     * Not yet stable
143    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
144        where
145            Self: Sized,
146            F: FnMut(B, Self::Item) -> R,
147            R: core::ops::Try<Output = B>, { Cannot use this because it's unstable
148
149    }
150    */
151
152    fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
153    where
154        Self: Sized,
155        F: FnMut(Acc, Self::Item) -> Acc,
156    {
157        let mut had_element = false;
158        if let Some(a) = self.a {
159            acc = a.fold(acc, |acc, item| {
160                had_element = true;
161                f(acc, item)
162            });
163        }
164        if had_element {
165            // No need to reset b - this function consumes self
166            return acc;
167        }
168
169        // Once again, it's fine to exclusively depend on `b` being `None` to determine if `a`
170        // ever had any values - even if at the point of calling this function it didn't, it
171        // should only ever have been advanced by this iterator in the past and hence `b` would
172        // have been set to `None`
173        if let Some(b) = self.b {
174            acc = b.fold(acc, f);
175        }
176        acc
177    }
178
179    /*
180    #[inline]
181    fn advance_by(&mut self, mut n: usize) -> Result<(), core::num::NonZero<usize>> {
182        if let Some(ref mut a) = self.a {
183            n = match (a.advance_by(n), n) {
184                // `a` actually did not advance at all, and there were no elements.
185                (Ok(()), 0) => return Ok(()),
186                // `a` failed to advance any amount, meaning it was an empty iterator (if it wasn't
187                // earlier, then `b` would have already been destroyed and that's ok).
188                // We destroy `a` for cleanup and fusion reasons.
189                (Err(k), tried) if tried == k.get() => {
190                    self.a = None;
191                    tried
192                }
193                (Ok(()), a_advanced_by) => {
194                    // `a` finished (though not actually "completed completed") with a
195                    // nonzero advancement count. This means it isn't empty, and we need to
196                    // destroy `b`.
197                    self.b = None;
198                    return Ok(());
199                },
200                // `a` failed to complete, but it did manage to advance. This still means that `a`
201                // is nonempty, and `b` should be destroyed. This also means *we* cannot advance
202                // further, so should forward up the error (also destroy `a` again.
203                (Err(k), tried) => {
204                    self.a = None;
205                    self.b = None;
206                    return Err(k)
207                }
208            };
209        }
210
211        if let Some(ref mut b) = self.b {
212            return b.advance_by(n);
213        }
214
215        // Nothing could actually do anything with `advance_by`, as we have no more iterators,
216        // so make it all error-y anyway if the advancement is not zero
217        NonZero::new(n).map_or(Ok(()), Err)
218    }
219    Cannot currently implement because unstable lol
220    */
221
222    /* Can't easily do any "proper" better-than-default implementation without using
223     * unstable features. TODO: still implement this
224    fn nth(&mut self, n: usize) -> Option<Self::Item> {
225
226    }
227    */
228
229    #[inline]
230    fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
231    where
232        Self: Sized,
233        P: FnMut(&Self::Item) -> bool,
234    {
235        let mut did_have_elements = false;
236        // Run through `a`. We've injected our boolean into the predicate, so we can determine
237        // if `a` ever called it (which it would have to do at least once if it had any elements)
238        let a_found = and_then_or_clear(
239            &mut self.a,
240            |a| {
241                a.find(|v| {
242                    did_have_elements = true;
243                    predicate(v)
244                })
245            },
246            || {},
247        );
248        if did_have_elements {
249            self.b = None;
250            return a_found;
251        }
252        // Run find on `b`. `b` would be `None` if `a` had ever had any elements
253        self.b.as_mut()?.find(predicate)
254    }
255
256    #[inline]
257    fn last(self) -> Option<Self::Item>
258    where
259        Self: Sized,
260    {
261        // We get the last of `a`, if `a` is not None
262        let a_last = self.a.and_then(Iterator::last);
263        // If this was Some, then `b` must be cleared. If it was `None`, then `b` was either
264        // cleared earlier (by `a` not being empty, and being run through), or `a` is empty and `b`
265        // is set to Some and can be used directly.
266        //
267        // We are actually consuming self, so no need to update anything.
268        if a_last.is_some() {
269            return a_last;
270        }
271
272        self.b.and_then(Iterator::last)
273    }
274
275    #[inline]
276    fn size_hint(&self) -> (usize, Option<usize>) {
277        match (&self.a, &self.b) {
278            (None, None) => (0, Some(0)),
279            (None, Some(b)) => b.size_hint(),
280            (Some(a), None) => a.size_hint(),
281            (Some(a), Some(b)) => {
282                // If `a` has a nonzero lower bound, then we know `b` will be removed.
283                // If `a` has a zero upper bound, then we know `b` is all that will be iterated
284                // If `b` has a zero upper bound, then we know `a` is all that will be iterated
285                // If `b` has a nonzero lower bound, then we know that if iterating backwards, `a`
286                // will not be iterated. However, size_hint is for forward iteration.
287                // Other than this, we can guaruntee that the lower bound is one of the two (we can
288                // be safe by picking minimum), and the upper bound is one of the two (we can be
289                // safe by picking maximum, or `None` if either of them have `None`)
290                match (a.size_hint(), b.size_hint()) {
291                    (a_size_hint @ (1.., _), _) => a_size_hint,
292                    ((_, Some(0)), b_size_hint) => b_size_hint,
293                    (a_size_hint, (_, Some(0))) => a_size_hint,
294                    (
295                        (a_lower_bound, maybe_a_upper_bound),
296                        (b_lower_bound, maybe_b_upper_bound),
297                    ) => {
298                        let maybe_upper_bound = match (maybe_a_upper_bound, maybe_b_upper_bound) {
299                            (Some(a_upper), Some(b_upper)) => Some(a_upper.max(b_upper)),
300                            _ => None,
301                        };
302                        let lower_bound = a_lower_bound.min(b_lower_bound);
303                        (lower_bound, maybe_upper_bound)
304                    }
305                }
306            }
307        }
308    }
309}
310
311impl<A, B> DoubleEndedIterator for EmptyFallbackChain<A, B>
312where
313    A: DoubleEndedIterator,
314    B: DoubleEndedIterator<Item = A::Item>,
315{
316    #[inline]
317    fn next_back(&mut self) -> Option<Self::Item> {
318        // Implement the same as `next`, but flip which thing gets called and reset.
319        and_then_or_clear(&mut self.b, DoubleEndedIterator::next_back, || {
320            self.a = None;
321        })
322        .or_else(|| self.a.as_mut()?.next_back())
323    }
324
325    /* unstable
326    fn advance_back_by(&mut self, n: usize) -> Result<(), core::num::NonZero<usize>> {}
327    */
328
329    /* Cannot easily implement without unstable advance_back_by - TODO: implement
330    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
331
332    }*/
333
334    #[inline]
335    fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
336    where
337        Self: Sized,
338        P: FnMut(&Self::Item) -> bool,
339    {
340        let mut had_any_elements = false;
341        // Run the find function, injecting into the predicate - which must be called
342        // at least once for any non-empty iterator.
343        let b_found = and_then_or_clear(
344            &mut self.b,
345            |b| {
346                b.rfind(|v| {
347                    had_any_elements = true;
348                    predicate(v)
349                })
350            },
351            || {},
352        );
353        if had_any_elements {
354            self.a = None;
355            return b_found;
356        }
357        self.a.as_mut()?.rfind(predicate)
358    }
359
360    /* unstable
361    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
362        where
363            Self: Sized,
364            F: FnMut(B, Self::Item) -> R,
365            R: core::ops::Try<Output = B>, {
366
367    }
368    */
369
370    fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
371    where
372        Self: Sized,
373        F: FnMut(Acc, Self::Item) -> Acc,
374    {
375        // This function is consuming, so we don't need to worry much about disposing of
376        // anything, just returning when needed :)
377        let mut had_any_elements = false;
378        if let Some(b) = self.b {
379            acc = b.rfold(acc, |acc, item| {
380                had_any_elements = true;
381                f(acc, item)
382            });
383        }
384        if had_any_elements {
385            // Consuming function, no need to deinit `a`
386            return acc;
387        }
388
389        if let Some(a) = self.a {
390            acc = a.rfold(acc, f);
391        }
392        acc
393    }
394}
395
396/// Execute the given function on the option, clearing the option if the output from the function
397/// was [`None`]. Also allows providing a callback to run if the output of `f` was `Some`.
398///
399/// This is pretty much identical to the function inside the standard library, except with added
400/// callback.
401#[inline]
402fn and_then_or_clear<T, U>(
403    resetting_input: &mut Option<T>,
404    with_some_input: impl FnOnce(&mut T) -> Option<U>,
405    on_some: impl FnOnce(),
406) -> Option<U> {
407    let output = with_some_input(resetting_input.as_mut()?);
408    if output.is_none() {
409        *resetting_input = None;
410    } else {
411        on_some();
412    };
413    output
414}
415
416/// Trait for extending [`Iterator`]s with methods to create [`EmptyFallbackChain`] iterators.
417pub trait IteratorExt: Iterator {
418    /// Takes two iterators and creates a new iterator that runs through the second only if the
419    /// first produces no output. Can take anything implementing [`IntoIterator`] as a second
420    /// argument (as long as it produces an iterator over the same type).
421    ///
422    /// `empty_fallback_chain()` will return a new iterator which will iterate over this (first) iterator - if
423    /// it produces any values, then the second iterator is dropped. However, if the first iterator doesn't 
424    /// produce any values, then the second iterator is iterated over instead (i.e. "as a
425    /// fallback").
426    ///
427    /// In other words, it links two iterators in a chain, but only if the first is empty. 
428    ///
429    /// This also applies in reverse direction when iterating backwards (i.e. with [`DoubleEndedIterator::next_back`], 
430    /// the second iterator is attempted to be iterated backwards first - only if nothing is
431    /// emitted, is the first iterator then iterated backwards instead, else the first iterator is simply dropped).
432    ///
433    /// # Examples
434    ///
435    /// Basic usage:
436    /// ```
437    /// use empty_fallback_chain::prelude::*;
438    /// let higher_priority = [1, 2, 3];
439    /// let lower_priority = [4, 5, 6];
440    ///
441    /// let iter = higher_priority.into_iter().empty_fallback_chain(lower_priority.into_iter());
442    /// assert_eq!(iter.collect::<Vec<_>>(), vec![1, 2, 3]);
443    /// ```
444    ///
445    /// The major feature of [`EmptyFallbackChain`] is that if the first iterator produces
446    /// no values, then the second iterator will be used instead.
447    /// ```
448    /// use empty_fallback_chain::IteratorExt as _;
449    ///
450    /// let higher_priority = [1, 3, 5];
451    /// let lower_priority = [10, 11, 78];
452    ///
453    /// /// Filter for even numbers - no data in the higher priority iterator matches this,
454    /// /// so when the filtered version is used as the first half of an `EmptyFallbackChain`,
455    /// /// the "fallback" iterator is what's used.
456    /// fn even(v: &u32) -> bool {
457    ///     v % 2 == 0
458    /// }
459    ///
460    /// let iter = higher_priority.into_iter().filter(even)
461    ///     .empty_fallback_chain(lower_priority.into_iter());
462    /// assert_eq!(iter.collect::<Vec<_>>(), vec![10, 11, 78]);
463    /// ```
464    ///
465    /// If the higher priority iterator produces *any* values, then the lower priority iterator is
466    /// never used. For example, with a filter that doesn't remove all of the higher-priority
467    /// information:
468    /// ```
469    /// use empty_fallback_chain::prelude::*;
470    ///
471    /// let higher_priority = [1, 3, 5];
472    /// let lower_priority = [10, 11, 78];
473    ///
474    /// fn incomplete_higher_filter(v: &u32) -> bool {
475    ///    *v != 3
476    /// }
477    ///
478    /// let iter = higher_priority.into_iter().filter(incomplete_higher_filter)
479    ///     .empty_fallback_chain(lower_priority.into_iter());
480    /// assert_eq!(iter.collect::<Vec<_>>(), vec![1, 5]);
481    /// ```
482    ///
483    /// This can be used to create incredibly powerful, lazily evaluated, fallback systems.
484    /// If you use multiple [`EmptyFallbackChain`] in sequence, you can create a sort of
485    /// "iterator priority" construction.
486    /// ```
487    /// use empty_fallback_chain::prelude::*;
488    ///
489    /// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
490    /// pub struct Contact {
491    ///     pub name: &'static str,
492    ///     pub email: &'static str,
493    ///     pub pronouns: &'static str
494    /// }
495    ///
496    ///# impl Contact {
497    ///#    /// Just example - You'd probably use owned, interned, or referenced strings
498    ///#    /// here.
499    ///#    pub const fn new(
500    ///#        name: &'static str,
501    ///#        email: &'static str,
502    ///#        pronouns: &'static str
503    ///#    ) -> Self {
504    ///#        Self { name, email, pronouns }
505    ///#    }
506    ///# }
507    /// // Example conditions
508    /// fn is_tuesday() -> bool { true }
509    /// fn is_wednesday() -> bool { false }
510    /// fn is_weekend() -> bool { false }
511    ///
512    /// use Contact as C;
513    /// use core::iter as iter;
514    ///
515    /// const bob: C = C::new("Bob Angie", "the-eponymous-bob@example.com", "he/him");
516    /// const tracey: C = C::new("Tracy Mill", "tracy-mill@corpo.example.com", "she/her");
517    /// const alan: C = C::new("Alan", "alanspace@example.com", "he/him");
518    /// const matriss: C = C::new("Matriss Karisle", "matriss@example.com", "they/them");
519    /// const charlie: C = C::new("Charlie Stone", "charlie-charlie@example.com", "she/her");
520    /// const harri: C = C::new("Harri", "harri-up@example.com", "they/she");
521    /// const mel: C = C::new("Mel", "mel@corpo.example.com", "she/her");
522    /// const troy: C = C::new("Troy", "helenofcity@example.com", "he/him");
523    ///
524    /// // Define the contact lists as functions producing iterators, in order of preference.
525    /// // In reality, you'd use some better means of determining availability, but the principle
526    /// // of using fallbacks is sound, and can be used for many scenarios
527    ///
528    /// fn emergency_contacts() -> impl Iterator<Item = Contact> {
529    ///     iter::empty()
530    ///         .chain(iter::once(troy).filter(|_| !is_tuesday() && !is_weekend()))
531    ///         .chain(iter::once(charlie).filter(|_| !is_weekend()))
532    ///         .chain([bob, matriss, harri].into_iter().filter(|_| !is_tuesday() &&
533    ///             !is_wednesday()))
534    /// }
535    ///
536    /// fn distant_family_contacts() -> impl Iterator<Item = Contact> {
537    ///     // fill in here
538    ///#    iter::empty()
539    ///#        .chain(iter::once(tracey).filter(|_| !is_weekend() && !is_tuesday()))
540    /// }
541    ///
542    /// fn corpo_contacts() -> impl Iterator<Item = Contact> {
543    ///     // fill in here
544    ///#    iter::empty()
545    ///#        .chain(iter::once(mel).filter(|_| !is_weekend()))
546    ///#        .chain(iter::once(tracey))
547    /// }
548    ///
549    /// fn friendly_evening_contacts() -> impl Iterator<Item = Contact> {
550    ///     // fill in here
551    ///#    iter::empty()
552    ///#        .chain([matriss, harri, mel].into_iter()
553    ///#            .filter(|_| !is_weekend() && !is_tuesday()))
554    ///#        .chain([alan, troy, charlie].into_iter()
555    ///#            .filter(|_| !is_weekend() && !is_wednesday()))
556    /// }
557    ///
558    /// // Then, build contact scenarios, using `empty_fallback_chain`
559    /// // If there are no contacts available for emergency situations, then
560    /// // this will iterate for contacts who can just be messaged for a "friendly evening".
561    /// // If that fails, then it will iterate over all distant family contacts.
562    /// fn i_have_an_emergency() -> impl Iterator<Item = Contact> {
563    ///     emergency_contacts()
564    ///         .empty_fallback_chain(friendly_evening_contacts())
565    ///         .empty_fallback_chain(distant_family_contacts())
566    ///
567    /// }
568    ///
569    /// fn i_want_a_friendly_time() -> impl Iterator<Item = Contact> {
570    ///     friendly_evening_contacts()
571    ///         .empty_fallback_chain(distant_family_contacts())
572    ///         .empty_fallback_chain(corpo_contacts())
573    /// }
574    ///
575    /// fn i_am_having_an_existential_crisis() -> impl Iterator<Item = Contact> {
576    ///     // fill in here
577    ///#    distant_family_contacts()
578    ///#        .empty_fallback_chain(friendly_evening_contacts())
579    /// }
580    /// ```
581    #[inline]
582    fn empty_fallback_chain<U>(self, other: U) -> EmptyFallbackChain<Self, U::IntoIter>
583    where
584        Self: Sized,
585        U: IntoIterator<Item = Self::Item>,
586    {
587        EmptyFallbackChain::new(self, other.into_iter())
588    }
589
590    /// Provide an empty fallback chain to this iterator, but only optionally so.
591    ///
592    /// Should it be a common case that you wish to only provide an empty fallback sometimes but
593    /// not others, then this function will let you efficiently create an [`EmptyFallbackChain`]
594    /// where the second iterator can be set to empty easily by just passing [`None`], equivalent
595    /// to there being no fallback, or a fallback which produces no iterator items.
596    ///
597    /// This creates less type-nesting and less indirection than using some other mechanisms to
598    /// "optionally" iterate something. Note that should you wish to provide [`None`] directly as a
599    /// parameter, you may need to use the `::<>` turbofish syntax to manage type deductions - use
600    /// any iterator that makes sense in the context here, as you will be setting it to [`None`]
601    /// anyway.
602    ///
603    /// # Basic Illustration
604    /// ```rust
605    /// use empty_fallback_chain::IteratorExt as _;
606    /// use core::iter::Empty;
607    ///
608    /// fn maybe_empty_fb<A: IntoIterator, B: IntoIterator<Item = A::Item>>(a: A, b: Option<B>) -> Vec<A::Item> {
609    ///     a.into_iter().maybe_empty_fallback_chain(b.map(IntoIterator::into_iter)).collect::<Vec<_>>()
610    /// }
611    ///
612    /// assert_eq!(maybe_empty_fb([1,2,3], Some([4, 5, 6])), vec![1, 2, 3]);
613    /// assert_eq!(maybe_empty_fb::<_, Empty<usize>>([1,2,3], None), vec![1, 2, 3]);
614    /// assert_eq!(maybe_empty_fb([], Some([4, 5, 6])), vec![4, 5, 6]);
615    /// assert_eq!(maybe_empty_fb::<_, Empty<usize>>([], None), vec![]);
616    /// ```
617    ///
618    /// # Conditionally Providing Fallback
619    /// ```rust
620    /// use empty_fallback_chain::{IteratorExt as _, EmptyFallbackChain};
621    /// use core::iter;
622    ///
623    /// fn apply_fallback_conditionally(
624    ///     a: impl IntoIterator<Item = usize>,
625    ///     do_fallback: bool
626    /// ) -> impl Iterator<Item = usize> {
627    ///     if do_fallback {
628    ///         a.into_iter().empty_fallback_chain([3, 4, 5].iter().copied())
629    ///     } else {
630    ///         // Note here that we need to provide some help with deduction by providing the
631    ///         // outermost iterator of the chain as a hint, because `maybe_empty_fallback_chain`
632    ///         // takes an `IntoIterator` as it's parameter and then uses the associated
633    ///         // `IntoIter` type, rather than only taking `Iterator`s
634    ///         //
635    ///         // Another way to solve this problem is to only use one call to
636    ///         // `maybe_empty_fallback_chain`, and unify the `Some` and `None` cases into a
637    ///         // single `Option` beforehand.
638    ///         a.into_iter().maybe_empty_fallback_chain::<iter::Copied<_>>(None)
639    ///     }
640    /// }
641    ///
642    /// assert_eq!(apply_fallback_conditionally([1, 2], true).collect::<Vec<_>>(), vec![1, 2]);
643    /// assert_eq!(apply_fallback_conditionally([], true).collect::<Vec<_>>(), vec![3, 4, 5]);
644    /// assert_eq!(apply_fallback_conditionally([1, 2], false).collect::<Vec<_>>(), vec![1, 2]);
645    /// assert_eq!(apply_fallback_conditionally([], false).collect::<Vec<_>>(), vec![]);
646    /// ```
647    #[inline]
648    fn maybe_empty_fallback_chain<U>(
649        self,
650        other: Option<U>,
651    ) -> EmptyFallbackChain<Self, U::IntoIter>
652    where
653        Self: Sized,
654        U: IntoIterator<Item = Self::Item>,
655    {
656        EmptyFallbackChain::new_with_pre_empty(Some(self), other.map(IntoIterator::into_iter))
657    }
658}
659
660impl<T: Iterator + ?Sized> IteratorExt for T {}
661
662pub mod prelude {
663    pub use super::IteratorExt as _;
664}
665
666#[cfg(test)]
667mod tests {
668    use core::iter;
669
670    fn none_iter<T: Iterator>() -> iter::Flatten<core::option::IntoIter<T>> {
671        None.into_iter().flatten()
672    }
673
674    fn some_iter<T: Iterator>(t: T) -> iter::Flatten<core::option::IntoIter<T>> {
675        Some(t).into_iter().flatten()
676    }
677
678    use super::*;
679    /// Make the "first" iterator to compose [`make_conditional_iter`]
680    fn make_first_iter() -> impl DoubleEndedIterator<Item = u32> + Clone {
681        [0].into_iter()
682    }
683
684    /// Make the "second" iterator to compose [`make_conditional_iter`]
685    fn make_second_iter() -> impl DoubleEndedIterator<Item = u32> + Clone {
686        [10, 11].into_iter()
687    }
688
689    /// Make the "third" iterator to compose [`make_conditional_iter`]
690    fn make_third_iter() -> impl DoubleEndedIterator<Item = u32> + Clone {
691        [20, 21, 22, 23, 24, 25].into_iter()
692    }
693
694    /// All values that might be emitted from an iterator made by [`make_conditional_iter`]
695    /// Not intended for direct comparison, but just for getting all the values.
696    fn make_all_values_iter() -> impl Iterator<Item = u32> + Clone {
697        make_first_iter()
698            .chain(make_second_iter())
699            .chain(make_third_iter())
700    }
701
702    /// Get a value not present in any possible [`make_conditional_iter`] combination.
703    fn non_present_value() -> u32 {
704        make_all_values_iter().max().unwrap() + 1
705    }
706
707    /// Make an "equivalent" known-good iterator for the given 3-boolean configuration,
708    /// only for the forward-order though
709    fn make_ideal_equivalent_iter_for(
710        include_values: [bool; 3],
711    ) -> impl Iterator<Item = u32> + Clone {
712        match include_values {
713            [true, _, _] => some_iter(make_first_iter())
714                .chain(none_iter())
715                .chain(none_iter()),
716            [false, true, _] => none_iter()
717                .chain(some_iter(make_second_iter()))
718                .chain(none_iter()),
719            [false, false, true] => none_iter()
720                .chain(none_iter())
721                .chain(some_iter(make_third_iter())),
722            [false, false, false] => none_iter().chain(none_iter()).chain(none_iter()),
723        }
724    }
725
726    /// Make an "equivalent" known-good (for the reverse direction) [`DoubleEndedIterator`] for the
727    /// given 3-boolean configuration, only for the reverse order functions though.
728    fn make_ideal_equivalent_reverse_iter_for(
729        include_values: [bool; 3],
730    ) -> impl DoubleEndedIterator<Item = u32> + Clone {
731        match include_values {
732            [_, _, true] => none_iter()
733                .chain(none_iter())
734                .chain(some_iter(make_third_iter())),
735            [_, true, false] => none_iter()
736                .chain(some_iter(make_second_iter()))
737                .chain(none_iter()),
738            [true, false, false] => some_iter(make_first_iter())
739                .chain(none_iter())
740                .chain(none_iter()),
741            [false, false, false] => none_iter().chain(none_iter()).chain(none_iter()),
742        }
743    }
744
745    /// Create a 3 element iterator chained with [`EmptyFallbackChain`] and where each given
746    /// subiterator either has values or does not depending on the booleans.
747    ///
748    /// The values in question are, if present, for the iterators in order:
749    /// * `[0]`,
750    /// * `[10, 11]`
751    /// * `[20, 21, 22, 23, 24, 25]`
752    fn make_conditional_iter(
753        include_values: [bool; 3],
754    ) -> impl DoubleEndedIterator<Item = u32> + Clone {
755        let first_iter = make_first_iter().filter(move |_| include_values[0]);
756        let second_iter = make_second_iter().filter(move |_| include_values[1]);
757        let third_iter = make_third_iter().filter(move |_| include_values[2]);
758        first_iter
759            .empty_fallback_chain(second_iter)
760            .empty_fallback_chain(third_iter)
761    }
762
763    /// Compare the functionality of a pair of iterators that should be "equivalent"
764    /// This means basic things, but also the more advanced iterator methods.
765    ///
766    /// Note that this will not compare [`DoubleEndedIterator`] methods - because the equivalent
767    /// "known good" iterator might be different for the opposite direction.
768    fn compare_iters(
769        known_good: impl Iterator<Item = u32> + Clone,
770        to_test: impl Iterator<Item = u32> + Clone,
771    ) {
772        // Test contents
773        assert_eq!(
774            known_good.clone().collect::<Vec<_>>(),
775            to_test.clone().collect::<Vec<_>>()
776        );
777
778        assert_eq!(known_good.clone().count(), to_test.clone().count());
779
780        assert_eq!(
781            known_good.clone().fold(3, |a, b| a + b),
782            to_test.clone().fold(3, |a, b| a + b)
783        );
784
785        for possible_value in make_all_values_iter().chain(iter::once(non_present_value())) {
786            assert_eq!(
787                known_good.clone().find(|v| *v == possible_value),
788                to_test.clone().find(|v| *v == possible_value)
789            )
790        }
791
792        assert_eq!(known_good.last(), to_test.last());
793    }
794
795    /// Compare specifically the reverse-based functionality of a pair of double ended iterators.
796    /// This is separated out from [`compare_iters`] because of divergent inverse behaviour which
797    /// means there is a different "ideal" model for the inverse mode.
798    fn compare_inverse_iters(
799        known_good: impl DoubleEndedIterator<Item = u32> + Clone,
800        to_test: impl DoubleEndedIterator<Item = u32> + Clone,
801    ) {
802        // Test inverse contents.
803        assert_eq!(
804            known_good.clone().rev().collect::<Vec<_>>(),
805            to_test.clone().rev().collect::<Vec<_>>()
806        );
807
808        // Test reverse-find
809        for possible_value in make_all_values_iter().chain(iter::once(non_present_value())) {
810            assert_eq!(
811                known_good.clone().rfind(|v| *v == possible_value),
812                to_test.clone().rfind(|v| *v == possible_value)
813            );
814        }
815
816        // Test rfold
817        assert_eq!(
818            known_good.rfold(3, |acc, v| acc + v),
819            to_test.rfold(3, |acc, v| acc + v)
820        );
821    }
822
823    /// Run tests for the [`make_conditional_iter`] generated by the given boolean triplet, against
824    /// the "ideal" iterator that it should be equivalent to if [`EmptyFallbackChain`] works
825    /// correctly.
826    fn compare_boolean_made_iters(include_values: [bool; 3]) {
827        compare_iters(
828            make_ideal_equivalent_iter_for(include_values),
829            make_conditional_iter(include_values),
830        );
831    }
832
833    /// Run tests for the [`make_conditional_iter`] generated by the given boolean triplet, against
834    /// the "ideal" double ended iterator that it's inverse "double-ended" methods should be
835    /// equivalent to if [`EmptyFallbackChain`] works correctly.
836    fn compare_boolean_made_inverse_iters(include_values: [bool; 3]) {
837        compare_inverse_iters(
838            make_ideal_equivalent_reverse_iter_for(include_values),
839            make_conditional_iter(include_values),
840        )
841    }
842
843    #[test]
844    fn chained_priority_basics() {
845        for i0 in [false, true] {
846            for i1 in [false, true] {
847                for i2 in [false, true] {
848                    compare_boolean_made_iters([i0, i1, i2]);
849                    compare_boolean_made_inverse_iters([i0, i1, i2]);
850                }
851            }
852        }
853    }
854}
855
856// This Source Code Form is subject to the terms of the Mozilla Public
857//  License, v. 2.0. If a copy of the MPL was not distributed with this
858//  file, You can obtain one at http://mozilla.org/MPL/2.0/.