use std::fmt::Debug;
use std::iter;
#[cfg(test)]
mod tests;
#[must_use]
pub enum ContainsAtLeastOrdered<T> {
Yes,
No { not_found: Vec<T> },
}
impl<T: Debug> ContainsAtLeastOrdered<T> {
pub fn assert_this(&self) {
match self {
Self::Yes => assert!(true),
Self::No {
not_found: remaining_elements,
} => {
assert!(false, "Missing elements: {:?}", remaining_elements)
}
}
}
pub fn assert_invalid(&self) {
match self {
Self::Yes => assert!(
false,
"Expected assertion to be rejected, but it was accepted. Asserted on type {:?}.",
core::any::type_name::<ContainsAtLeastOrdered<T>>()
),
Self::No {
not_found: remaining_elements,
} => {
assert!(true, "Missing elements: {:?}", remaining_elements)
}
}
}
}
impl<T> ContainsAtLeastOrdered<T> {
pub fn elements_not_found(&self) -> Option<&[T]> {
match self {
Self::Yes => None,
Self::No { not_found } => Some(not_found.as_slice()),
}
}
}
impl<T> From<ContainsAtLeastOrdered<T>> for bool {
fn from(item: ContainsAtLeastOrdered<T>) -> Self {
matches!(item, ContainsAtLeastOrdered::Yes)
}
}
pub fn contains_at_least_ordered<I1, I2, T>(iter: I1, expected: I2) -> ContainsAtLeastOrdered<T>
where
I1: IntoIterator<Item = T>,
I2: IntoIterator<Item = T>,
T: PartialEq,
{
let mut expected = expected.into_iter().peekable();
if expected.peek().is_none() {
return ContainsAtLeastOrdered::Yes;
}
let mut expected_next = expected.next().unwrap();
for elem in iter {
if elem == expected_next && expected.peek().is_some() {
expected_next = expected.next().unwrap();
continue;
}
if elem == expected_next && expected.peek().is_none() {
return ContainsAtLeastOrdered::Yes;
}
}
let current = iter::once(expected_next);
ContainsAtLeastOrdered::No {
not_found: current.chain(expected).collect(),
}
}