use std::ops::Deref;
use either::Either;
use crate::{
predicate::{PurePredicate, SyncEvaluablePredicate},
Proven,
};
pub trait BinaryClassification<Subject> {
type LeftPredicate: BinaryClassPredicate<Subject, BinClassification = Self>;
type RightPredicate: BinaryClassPredicate<Subject, BinClassification = Self>;
}
pub trait BinaryClassPredicate<Subject>: PurePredicate<Subject> {
type BinClassification: BinaryClassification<Subject>;
}
pub struct BinaryClassified<Subject, Cln>(
pub Either<Proven<Subject, Cln::LeftPredicate>, Proven<Subject, Cln::RightPredicate>>,
)
where
Cln: BinaryClassification<Subject>;
impl<Subject: Clone, Cln> Clone for BinaryClassified<Subject, Cln>
where
Cln: BinaryClassification<Subject>,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<Subject: std::fmt::Debug, Cln> std::fmt::Debug for BinaryClassified<Subject, Cln>
where
Cln: BinaryClassification<Subject>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("BinaryClassified").field(&self.0).finish()
}
}
impl<Subject, Cln> BinaryClassified<Subject, Cln>
where
Cln: BinaryClassification<Subject>,
{
pub fn new(subject: Subject) -> Self
where
Cln::LeftPredicate: SyncEvaluablePredicate<Subject>,
{
Self(
match Proven::<Subject, Cln::LeftPredicate>::try_new(subject) {
Ok(left_proven) => Either::Left(left_proven),
Err(err) => unsafe { Either::Right(Proven::new_unchecked(err.into_parts().0)) },
},
)
}
pub fn as_inner(&self) -> &Subject {
match &self.0 {
Either::Left(l) => l.as_ref(),
Either::Right(r) => r.as_ref(),
}
}
pub fn into_inner(self) -> Subject {
match self.0 {
Either::Left(l) => l.into_subject(),
Either::Right(r) => r.into_subject(),
}
}
#[inline]
pub fn is_left_classified(&self) -> bool {
self.0.is_left()
}
#[inline]
pub fn is_right_classified(&self) -> bool {
self.0.is_right()
}
pub fn as_left_classified(&self) -> Option<&Proven<Subject, Cln::LeftPredicate>> {
match &self.0 {
Either::Left(left) => Some(left),
Either::Right(_) => None,
}
}
pub fn as_right_classified(&self) -> Option<&Proven<Subject, Cln::RightPredicate>> {
match &self.0 {
Either::Left(_) => None,
Either::Right(right) => Some(right),
}
}
}
impl<Subject, Cln> Deref for BinaryClassified<Subject, Cln>
where
Cln: BinaryClassification<Subject>,
{
type Target = Subject;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_inner()
}
}
impl<Subject, Cln> AsRef<Subject> for BinaryClassified<Subject, Cln>
where
Cln: BinaryClassification<Subject>,
{
#[inline]
fn as_ref(&self) -> &Subject {
self.as_inner()
}
}