use std::fmt;
use super::adapter::{DynTransformMatchAdapter, MatchAdapter, NegTransformMatchAdapter};
use super::wrap::MatchWrapper;
use super::{FormattedFailure, MatchOutcome, MatcherFormat};
pub trait TransformMatch {
type In;
type PosOut;
type NegOut;
type PosFail;
type NegFail;
fn match_pos(
self,
actual: Self::In,
) -> crate::Result<MatchOutcome<Self::PosOut, Self::PosFail>>;
fn match_neg(
self,
actual: Self::In,
) -> crate::Result<MatchOutcome<Self::NegOut, Self::NegFail>>;
}
pub trait Match<Actual> {
type Fail;
fn matches(&mut self, actual: &Actual) -> crate::Result<bool>;
fn fail(self, actual: Actual) -> Self::Fail;
}
pub trait DynTransformMatch {
type In;
type PosOut;
type NegOut;
fn match_pos(
self: Box<Self>,
actual: Self::In,
) -> crate::Result<MatchOutcome<Self::PosOut, FormattedFailure>>;
fn match_neg(
self: Box<Self>,
actual: Self::In,
) -> crate::Result<MatchOutcome<Self::NegOut, FormattedFailure>>;
}
pub type BoxTransformMatch<'a, In, PosOut, NegOut = PosOut> =
Box<dyn DynTransformMatch<In = In, PosOut = PosOut, NegOut = NegOut> + 'a>;
pub struct Matcher<'a, In, PosOut, NegOut = PosOut> {
inner: BoxTransformMatch<'a, In, PosOut, NegOut>,
}
impl<'a, In, PosOut, NegOut> fmt::Debug for Matcher<'a, In, PosOut, NegOut> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Matcher").finish_non_exhaustive()
}
}
impl<'a, Actual> Matcher<'a, Actual, Actual> {
pub fn new<M, Fmt>(matcher: M, format: Fmt) -> Self
where
M: Match<Actual> + 'a,
Fmt: MatcherFormat<Pos = M::Fail, Neg = M::Fail> + 'a,
Actual: 'a,
{
Self::transform(MatchAdapter::new(matcher), format)
}
pub fn neg<M, Fmt>(matcher: M, format: Fmt) -> Self
where
M: Match<Actual> + 'a,
Fmt: MatcherFormat<Pos = M::Fail, Neg = M::Fail> + 'a,
Actual: 'a,
{
Self::transform_neg(MatchAdapter::new(matcher), format)
}
}
impl<'a, In, PosOut, NegOut> Matcher<'a, In, PosOut, NegOut> {
pub fn transform<M, Fmt>(matcher: M, format: Fmt) -> Self
where
M: TransformMatch<In = In, PosOut = PosOut, NegOut = NegOut> + 'a,
Fmt: MatcherFormat<Pos = M::PosFail, Neg = M::NegFail> + 'a,
{
Self {
inner: Box::new(DynTransformMatchAdapter::new(matcher, format)),
}
}
pub fn transform_neg<M, Fmt>(matcher: M, format: Fmt) -> Self
where
M: TransformMatch<In = In, PosOut = NegOut, NegOut = PosOut> + 'a,
Fmt: MatcherFormat<Pos = M::NegFail, Neg = M::PosFail> + 'a,
{
Matcher::transform(NegTransformMatchAdapter::new(matcher), format)
}
pub fn wrapped<Fmt>(self, format: Fmt) -> Self
where
In: 'a,
PosOut: 'a,
NegOut: 'a,
Fmt: MatcherFormat<Pos = FormattedFailure, Neg = FormattedFailure> + 'a,
{
Self::transform(MatchWrapper::new(self), format)
}
pub fn into_box(self) -> BoxTransformMatch<'a, In, PosOut, NegOut> {
self.inner
}
}
impl<'a, In, PosOut, NegOut> DynTransformMatch for Matcher<'a, In, PosOut, NegOut> {
type In = In;
type PosOut = PosOut;
type NegOut = NegOut;
fn match_pos(
self: Box<Self>,
actual: Self::In,
) -> crate::Result<MatchOutcome<Self::PosOut, FormattedFailure>> {
self.inner.match_pos(actual)
}
fn match_neg(
self: Box<Self>,
actual: Self::In,
) -> crate::Result<MatchOutcome<Self::NegOut, FormattedFailure>> {
self.inner.match_neg(actual)
}
}