#![doc(hidden)]
#[macro_export]
#[doc(hidden)]
macro_rules! __field {
($($t:tt)*) => { $crate::field_internal!($($t)*) }
}
#[doc(hidden)]
#[macro_export]
macro_rules! field_internal {
($($t:ident)::+.$field:tt, $m:expr) => {{
use $crate::matchers::__internal::field_matcher;
field_matcher(
|o| {
match o {
$($t)::* { $field: value, .. } => Some(value),
#[allow(unreachable_patterns)]
_ => None,
}
},
&stringify!($field),
$m)
}};
}
#[doc(hidden)]
pub mod __internal {
use crate::{
description::Description,
matcher::{Describable, Matcher, MatcherResult},
};
use std::fmt::Debug;
#[doc(hidden)]
pub fn field_matcher<OuterT: Debug, InnerT: Debug, InnerMatcher: Matcher<InnerT>>(
field_accessor: fn(&OuterT) -> Option<&InnerT>,
field_path: &'static str,
inner: InnerMatcher,
) -> impl Matcher<OuterT> {
FieldMatcher { field_accessor, field_path, inner }
}
struct FieldMatcher<OuterT, InnerT, InnerMatcher> {
field_accessor: fn(&OuterT) -> Option<&InnerT>,
field_path: &'static str,
inner: InnerMatcher,
}
impl<OuterT: Debug, InnerT: Debug, InnerMatcher: Matcher<InnerT>> Matcher<OuterT>
for FieldMatcher<OuterT, InnerT, InnerMatcher>
{
fn matches(&self, actual: &OuterT) -> MatcherResult {
if let Some(value) = (self.field_accessor)(actual) {
self.inner.matches(value)
} else {
MatcherResult::NoMatch
}
}
fn explain_match(&self, actual: &OuterT) -> Description {
if let Some(actual) = (self.field_accessor)(actual) {
format!(
"which has field `{}`, {}",
self.field_path,
self.inner.explain_match(actual)
)
.into()
} else {
let formatted_actual_value = format!("{actual:?}");
let without_fields = formatted_actual_value.split('(').next().unwrap_or("");
let without_fields = without_fields.split('{').next().unwrap_or("").trim_end();
format!("which has the wrong enum variant `{without_fields}`").into()
}
}
}
impl<OuterT, InnerT, InnerMatcher: Describable> Describable
for FieldMatcher<OuterT, InnerT, InnerMatcher>
{
fn describe(&self, matcher_result: MatcherResult) -> Description {
format!(
"has field `{}`, which {}",
self.field_path,
self.inner.describe(matcher_result)
)
.into()
}
}
}