use std::{fmt::Display, ops::Not};
pub trait DirectMatch<V: ?Sized> {
type Output: DirectMatchResult;
fn criterium_match(&self, data: &V) -> Self::Output;
}
pub trait DirectMatchResult: Clone {
fn kind(&self) -> DirectMatchResultKind;
fn invert(self) -> Self;
fn new(value: bool) -> Self;
fn as_opt(&self) -> Option<bool> {
match self.kind() {
DirectMatchResultKind::False => Some(false),
DirectMatchResultKind::True => Some(true),
DirectMatchResultKind::Unknown => None,
DirectMatchResultKind::Error => None,
}
}
fn unwrap_or(&self, fallback: bool) -> bool {
self.as_opt().unwrap_or(fallback)
}
fn and(self, other: Self) -> Self {
if matches!(
self.kind(),
DirectMatchResultKind::True | DirectMatchResultKind::Error
) {
other
} else {
self
}
}
fn or(self, other: Self) -> Self {
if matches!(
self.kind(),
DirectMatchResultKind::True | DirectMatchResultKind::Error
) {
self
} else {
other
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DirectMatchResultKind {
False,
True,
Unknown,
Error,
}
impl DirectMatchResultKind {
#[inline]
pub fn is_true(&self) -> bool {
matches!(self, Self::True)
}
#[inline]
pub fn is_false(&self) -> bool {
matches!(self, Self::False)
}
#[inline]
pub fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
#[inline]
pub fn is_error(&self) -> bool {
matches!(self, Self::Error)
}
}
impl DirectMatchResult for bool {
fn kind(&self) -> DirectMatchResultKind {
match self {
true => DirectMatchResultKind::True,
false => DirectMatchResultKind::False,
}
}
fn as_opt(&self) -> Option<bool> {
Some(*self)
}
fn unwrap_or(&self, _fallback: bool) -> bool {
*self
}
fn and(self, other: Self) -> Self {
self && other
}
fn or(self, other: Self) -> Self {
self || other
}
fn new(value: bool) -> Self {
value
}
fn invert(self) -> Self {
!self
}
}
impl<T, E> DirectMatchResult for Result<T, E>
where
T: DirectMatchResult + Clone,
E: Clone,
{
fn as_opt(&self) -> Option<bool> {
match self {
Ok(v) => v.as_opt(),
Err(_) => None,
}
}
fn kind(&self) -> DirectMatchResultKind {
match self {
Ok(v) => v.kind(),
Err(_) => DirectMatchResultKind::Error,
}
}
fn new(value: bool) -> Self {
Ok(T::new(value))
}
fn invert(self) -> Self {
self.map(|v| v.invert())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MaybeDirectMatchResult {
Bool(bool),
Unknown,
}
impl DirectMatchResult for MaybeDirectMatchResult {
fn as_opt(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
Self::Unknown => None,
}
}
fn unwrap_or(&self, fallback: bool) -> bool {
match self {
Self::Bool(b) => *b,
Self::Unknown => fallback,
}
}
fn kind(&self) -> DirectMatchResultKind {
match self {
Self::Bool(true) => DirectMatchResultKind::True,
Self::Bool(false) => DirectMatchResultKind::False,
Self::Unknown => DirectMatchResultKind::Unknown,
}
}
fn new(value: bool) -> Self {
Self::Bool(value)
}
fn invert(self) -> Self {
!self
}
}
impl<T> DirectMatchResult for Option<T>
where
T: DirectMatchResult,
{
fn as_opt(&self) -> Option<bool> {
match self {
Self::Some(v) => v.as_opt(),
Self::None => None,
}
}
fn unwrap_or(&self, fallback: bool) -> bool {
match self {
Self::Some(v) => v.unwrap_or(fallback),
Self::None => fallback,
}
}
fn kind(&self) -> DirectMatchResultKind {
match self {
Self::Some(v) => v.kind(),
Self::None => DirectMatchResultKind::Unknown,
}
}
fn new(value: bool) -> Self {
Some(T::new(value))
}
fn invert(self) -> Self {
self.map(|v| v.invert())
}
}
impl Not for MaybeDirectMatchResult {
type Output = MaybeDirectMatchResult;
fn not(self) -> Self::Output {
match self {
Self::Bool(b) => Self::Bool(!b),
Self::Unknown => Self::Unknown,
}
}
}
impl From<Option<bool>> for MaybeDirectMatchResult {
fn from(value: Option<bool>) -> Self {
match value {
Some(b) => Self::Bool(b),
None => Self::Unknown,
}
}
}
impl From<MaybeDirectMatchResult> for Option<bool> {
fn from(value: MaybeDirectMatchResult) -> Self {
value.as_opt()
}
}
impl Display for MaybeDirectMatchResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bool(b) => b.fmt(f),
Self::Unknown => f.write_str("unknown"),
}
}
}