use super::{Destination, Role};
use crate::bounded::NonEmpty;
#[derive(Clone, Copy)]
pub(crate) enum JoinOrder<'roster, R> {
Offering,
Roster(&'roster [R]),
}
type Rows<'rows, T> = core::iter::Chain<core::iter::Once<&'rows T>, core::slice::Iter<'rows, T>>;
pub(crate) fn rows_under<T, R: Role, const N: usize>(
rows: &NonEmpty<T, N>,
role: R,
role_of: fn(&T) -> R,
) -> impl Iterator<Item = &T> {
rows.iter().filter(move |row| role_of(row) == role)
}
fn destination_role<R: Role>(
roster: &[R],
destination: Destination,
roster_at: &mut usize,
) -> Option<R> {
loop {
let role = *roster.get(*roster_at)?;
*roster_at = roster_at.saturating_add(1);
if role.destination() == destination {
return Some(role);
}
}
}
fn active_role<'rows, T, R: Role, const N: usize>(
rows: &'rows NonEmpty<T, N>,
roster: &[R],
destination: Destination,
roster_at: &mut usize,
active: &mut Option<R>,
under: &mut Rows<'rows, T>,
) -> Option<R> {
if let Some(role) = *active {
return Some(role);
}
let role = destination_role(roster, destination, roster_at)?;
*active = Some(role);
*under = rows.into_iter();
Some(role)
}
fn next_rostered<'rows, T, R: Role, const N: usize>(
rows: &'rows NonEmpty<T, N>,
roster: &[R],
destination: Destination,
role_of: fn(&T) -> R,
roster_at: &mut usize,
active: &mut Option<R>,
under: &mut Rows<'rows, T>,
) -> Option<&'rows T> {
loop {
let role = active_role(rows, roster, destination, roster_at, active, under)?;
if let Some(row) = under.find(|row| role_of(row) == role) {
return Some(row);
}
*active = None;
}
}
pub(crate) fn rows_to<'rows, T, R: Role, const N: usize>(
rows: &'rows NonEmpty<T, N>,
destination: Destination,
order: JoinOrder<'rows, R>,
role_of: fn(&T) -> R,
) -> impl Iterator<Item = &'rows T> {
let mut offering = rows.into_iter();
let mut roster_at = 0_usize;
let mut active = None;
let mut under = rows.into_iter();
core::iter::from_fn(move || match order {
JoinOrder::Offering => offering.find(|row| role_of(row).destination() == destination),
JoinOrder::Roster(roster) => next_rostered(
rows,
roster,
destination,
role_of,
&mut roster_at,
&mut active,
&mut under,
),
})
}