use std::fmt;
use crate::core::Match;
use super::Mismatch;
pub struct Pattern<'a, T> {
pattern: &'static str,
matches: Box<dyn for<'b> Fn(&'b T) -> bool + 'a>,
}
impl<'a, T> fmt::Debug for Pattern<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.pattern)
}
}
impl<'a, T> fmt::Display for Pattern<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.pattern)
}
}
impl<'a, T> Pattern<'a, T> {
#[doc(hidden)]
pub fn __new(pattern: &'static str, matches: impl for<'b> Fn(&'b T) -> bool + 'a) -> Self {
Self {
pattern,
matches: Box::new(matches),
}
}
pub fn matches(&self, value: &T) -> bool {
(self.matches)(value)
}
}
#[derive(Debug)]
pub struct PatternMatcher<'a, Actual> {
spec: Pattern<'a, Actual>,
}
impl<'a, Actual> PatternMatcher<'a, Actual> {
pub fn new(spec: Pattern<'a, Actual>) -> Self {
Self { spec }
}
}
impl<'a, 'b: 'a, Actual> Match<Actual> for PatternMatcher<'a, Actual> {
type Fail = Mismatch<Pattern<'a, Actual>, Actual>;
fn matches(&mut self, actual: &Actual) -> crate::Result<bool> {
Ok((self.spec.matches)(actual))
}
fn fail(self, actual: Actual) -> Self::Fail {
Mismatch {
expected: self.spec,
actual,
}
}
}
#[macro_export]
macro_rules! pattern {
($pattern:pat $( if $guard:expr )? $(,)?) => {
$crate::matchers::pattern::Pattern::__new(
stringify!($pattern $( if $guard )?),
|ref actual| match actual {
$pattern $( if $guard )? => true,
_ => false,
},
)
};
}