use core::{fmt, marker::PhantomData};
pub trait Predicate<T: ?Sized> {
fn check(value: &T) -> bool;
fn check_value(value: T) -> bool
where
T: Sized,
{
Self::check(&value)
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
}
pub trait PredicateExpected<T: ?Sized>: Predicate<T> {
#[must_use]
fn expected() -> Expected<T, Self> {
Expected::new()
}
}
impl<T: ?Sized, P: Predicate<T> + ?Sized> PredicateExpected<T> for P {}
pub struct Expected<T: ?Sized, P: Predicate<T> + ?Sized> {
value: PhantomData<T>,
predicate: PhantomData<P>,
}
impl<T: ?Sized, P: Predicate<T> + ?Sized> Default for Expected<T, P> {
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized, P: Predicate<T> + ?Sized> Expected<T, P> {
#[must_use]
pub const fn new() -> Self {
Self {
value: PhantomData,
predicate: PhantomData,
}
}
}
impl<T: ?Sized, P: Predicate<T> + ?Sized> fmt::Debug for Expected<T, P> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
P::expect_code(formatter)
}
}
impl<T: ?Sized, P: Predicate<T> + ?Sized> fmt::Display for Expected<T, P> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
P::expect(formatter)
}
}
pub trait Check {
fn satisfies<P: Predicate<Self> + ?Sized>(&self) -> bool {
P::check(self)
}
}
impl<T: ?Sized> Check for T {}