Trait empty_fallback_chain::IteratorExt
source · pub trait IteratorExt: Iterator {
// Provided method
fn empty_fallback_chain<U>(
self,
other: U,
) -> EmptyFallbackChain<Self, U::IntoIter> ⓘ
where Self: Sized,
U: IntoIterator<Item = Self::Item> { ... }
}
Expand description
Trait for extending Iterators with methods to create EmptyFallbackChain iterators.
Provided Methods§
sourcefn empty_fallback_chain<U>(
self,
other: U,
) -> EmptyFallbackChain<Self, U::IntoIter> ⓘ
fn empty_fallback_chain<U>( self, other: U, ) -> EmptyFallbackChain<Self, U::IntoIter> ⓘ
Takes two iterators and creates a new iterator that runs through the second only if the first produces no output. Can take anything implementing IntoIterator as a second argument.
empty_fallback_chain()
will return a new iterator which will iterate over the first iterator. If
it produces any values, then the second iterator is dropped. However, if it doesn’t, then
the second iterator is iterated over instead.
In other words, it links two iterators in a chain, but only if the first is empty.
§Examples
Basic usage:
use empty_fallback_chain::prelude::*;
let higher_priority = [1, 2, 3];
let lower_priority = [4, 5, 6];
let iter = higher_priority.into_iter().empty_fallback_chain(lower_priority.into_iter());
assert_eq!(iter.collect::<Vec<_>>(), vec![1, 2, 3]);
The major feature of EmptyFallbackChain
is that if the first iterator produces
no values, then the second iterator will be used instead.
use empty_fallback_chain::IteratorExt as _;
let higher_priority = [1, 3, 5];
let lower_priority = [10, 11, 78];
/// Filter for even numbers - no data in the higher priority iterator matches this,
/// so when the filtered version is used as the first half of an `EmptyFallbackChain`,
/// the "fallback" iterator is what's used.
fn even(v: &u32) -> bool {
v % 2 == 0
}
let iter = higher_priority.into_iter().filter(even)
.empty_fallback_chain(lower_priority.into_iter());
assert_eq!(iter.collect::<Vec<_>>(), vec![10, 11, 78]);
If the higher priority iterator produces any values, then the lower priority iterator is never used. For example, with a filter that doesn’t remove all of the higher-priority information:
use empty_fallback_chain::prelude::*;
let higher_priority = [1, 3, 5];
let lower_priority = [10, 11, 78];
fn incomplete_higher_filter(v: &u32) -> bool {
*v != 3
}
let iter = higher_priority.into_iter().filter(incomplete_higher_filter)
.empty_fallback_chain(lower_priority.into_iter());
assert_eq!(iter.collect::<Vec<_>>(), vec![1, 5]);
This can be used to create incredibly powerful, lazily evaluated, fallback systems.
If you use multiple EmptyFallbackChain
in sequence, you can create a sort of
“iterator priority” construction.
use empty_fallback_chain::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Contact {
pub name: &'static str,
pub email: &'static str,
pub pronouns: &'static str
}
// Example conditions
fn is_tuesday() -> bool { true }
fn is_wednesday() -> bool { false }
fn is_weekend() -> bool { false }
use Contact as C;
use core::iter as iter;
const bob: C = C::new("Bob Angie", "the-eponymous-bob@example.com", "he/him");
const tracey: C = C::new("Tracy Mill", "tracy-mill@corpo.example.com", "she/her");
const alan: C = C::new("Alan", "alanspace@example.com", "he/him");
const matriss: C = C::new("Matriss Karisle", "matriss@example.com", "they/them");
const charlie: C = C::new("Charlie Stone", "charlie-charlie@example.com", "she/her");
const harri: C = C::new("Harri", "harri-up@example.com", "they/she");
const mel: C = C::new("Mel", "mel@corpo.example.com", "she/her");
const troy: C = C::new("Troy", "helenofcity@example.com", "he/him");
// Define the contact lists as functions producing iterators, in order of preference.
// In reality, you'd use some better means of determining availability, but the principle
// of using fallbacks is sound, and can be used for many scenarios
fn emergency_contacts() -> impl Iterator<Item = Contact> {
iter::empty()
.chain(iter::once(troy).filter(|_| !is_tuesday() && !is_weekend()))
.chain(iter::once(charlie).filter(|_| !is_weekend()))
.chain([bob, matriss, harri].into_iter().filter(|_| !is_tuesday() &&
!is_wednesday()))
}
fn distant_family_contacts() -> impl Iterator<Item = Contact> {
// fill in here
}
fn corpo_contacts() -> impl Iterator<Item = Contact> {
// fill in here
}
fn friendly_evening_contacts() -> impl Iterator<Item = Contact> {
// fill in here
}
// Then, build contact scenarios, using `empty_fallback_chain`
// If there are no contacts available for emergency situations, then
// this will iterate for contacts who can just be messaged for a "friendly evening".
// If that fails, then it will iterate over all distant family contacts.
fn i_have_an_emergency() -> impl Iterator<Item = Contact> {
emergency_contacts()
.empty_fallback_chain(friendly_evening_contacts())
.empty_fallback_chain(distant_family_contacts())
}
fn i_want_a_friendly_time() -> impl Iterator<Item = Contact> {
friendly_evening_contacts()
.empty_fallback_chain(distant_family_contacts())
.empty_fallback_chain(corpo_contacts())
}
fn i_am_having_an_existential_crisis() -> impl Iterator<Item = Contact> {
// fill in here
}