#![doc(hidden)]
#[macro_export]
#[doc(hidden)]
macro_rules! __elements_are {
($($matcher:expr),* $(,)?) => {{
$crate::matchers::__internal_unstable_do_not_depend_on_these::ElementsAre::new(
vec![$(Box::new(
$crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
$matcher
)
)),*])
}}
}
#[doc(hidden)]
pub mod internal {
use crate::description::Description;
use crate::matcher::{Matcher, MatcherBase, MatcherResult};
use crate::matcher_support::zipped_iterator::zip;
use std::fmt::Debug;
#[doc(hidden)]
#[derive(MatcherBase)]
pub struct ElementsAre<'a, T: Debug + Copy> {
elements: Vec<Box<dyn Matcher<T> + 'a>>,
}
impl<'a, T: Debug + Copy> ElementsAre<'a, T> {
#[doc(hidden)]
pub fn new(elements: Vec<Box<dyn Matcher<T> + 'a>>) -> Self {
Self { elements }
}
}
impl<T: Debug + Copy, ContainerT: Debug + Copy> Matcher<ContainerT> for ElementsAre<'_, T>
where
ContainerT: IntoIterator<Item = T>,
{
fn matches(&self, actual: ContainerT) -> MatcherResult {
let mut zipped_iterator = zip(actual.into_iter(), self.elements.iter());
for (a, e) in zipped_iterator.by_ref() {
if e.matches(a).is_no_match() {
return MatcherResult::NoMatch;
}
}
if !zipped_iterator.has_size_mismatch() {
MatcherResult::Match
} else {
MatcherResult::NoMatch
}
}
fn explain_match(&self, actual: ContainerT) -> Description {
let actual_iterator = actual.into_iter();
let mut zipped_iterator = zip(actual_iterator, self.elements.iter());
let mut mismatches = Vec::new();
for (idx, (a, e)) in zipped_iterator.by_ref().enumerate() {
if e.matches(a).is_no_match() {
mismatches.push(format!("element #{idx} is {a:?}, {}", e.explain_match(a)));
}
}
if mismatches.is_empty() {
if !zipped_iterator.has_size_mismatch() {
"whose elements all match".into()
} else {
format!("whose size is {}", zipped_iterator.left_size()).into()
}
} else if mismatches.len() == 1 {
let mismatches = mismatches.into_iter().collect::<Description>();
format!("where {mismatches}").into()
} else {
let mismatches = mismatches.into_iter().collect::<Description>();
format!("where:\n{}", mismatches.bullet_list().indent()).into()
}
}
fn describe(&self, matcher_result: MatcherResult) -> Description {
format!(
"{} elements:\n{}",
if matcher_result.into() { "has" } else { "doesn't have" },
&self
.elements
.iter()
.map(|matcher| matcher.describe(MatcherResult::Match))
.collect::<Description>()
.enumerate()
.indent()
)
.into()
}
}
}