use crate::*;
use either::Either;
use std::borrow::Borrow;
use std::fmt::Debug;
use std::fmt::Display;
use std::hash::Hash;
use std::ops::Deref;
use std::ops::Range;
#[derive(Debug, Enum, AsRef)]
pub enum Reducer<T> {
Input(Input<T>),
Conclusion(Conclusion<T>),
}
impl<T> From<Input<T>> for Reducer<T> {
fn from(input: Input<T>) -> Self { Self::Input(input) }
}
impl<T> From<Conclusion<T>> for Reducer<T> {
fn from(conclusion: Conclusion<T>) -> Self { Self::Conclusion(conclusion) }
}
impl<T> Reducer<T> {
pub(crate) fn overlaps(&self, other: &Self) -> bool {
let range_a = self.range();
let range_b = other.range();
range_a.start < range_b.end && range_a.end > range_b.start
}
pub fn value(&self) -> &T {
match self {
Self::Input(input) => &input.value(),
Self::Conclusion(conclusion) => conclusion.value(),
}
}
pub fn antecedents(&self) -> impl Iterator<Item = &Reducer<T>> + DoubleEndedIterator {
self.conclusion().into_iter().flat_map(Conclusion::antecedents)
}
pub fn antecedents_flattened(&self) -> Box<dyn '_ + Iterator<Item = &Reducer<T>>>
where T: Hash {
Box::new(self.antecedents().flat_map(|antecedent| {
if Digest::from(antecedent.value()) == Digest::from(self.value()) {
Either::Left(antecedent.antecedents_flattened())
} else {
Either::Right(std::iter::once(antecedent))
}
}))
}
pub fn origin(&self) -> Option<&Ruleset<T>> {
match self {
Self::Input(input) => None,
Self::Conclusion(conclusion) => Some(conclusion.origin()),
}
}
}
impl<T> AsRef<T> for Reducer<T> {
fn as_ref(&self) -> &T { self.value() }
}
impl<T> Borrow<T> for Reducer<T> {
fn borrow(&self) -> &T { self.value() }
}
impl<T> Deref for Reducer<T> {
type Target = T;
fn deref(&self) -> &Self::Target { self.value() }
}
impl<T> Addressable for Reducer<T> {
fn range(&self) -> Range<usize> {
match self {
Self::Input(input) => input.range(),
Self::Conclusion(conclusion) => conclusion.range(),
}
}
}
impl<T> ChildMaybe for Reducer<T> {
type Mother = Reducible<T>;
type Father = Reducer<T>;
fn mother_maybe(&self) -> Option<&Self::Mother> { self.conclusion().map(Child::mother) }
fn father_maybe(&self) -> Option<&Self::Father> { self.conclusion().map(Child::father) }
}
impl<T> Display for Reducer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let precision = f.precision();
let string = Digest::from(self).to_string();
let string = &string[0..(precision.unwrap_or(string.len()))];
write!(f, "{string}")?;
Ok(())
}
}
impl<T> Hash for Reducer<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Input(input) => Hash::hash(input, state),
Self::Conclusion(conclusion) => Hash::hash(conclusion, state),
}
}
}
impl<T> Clone for Reducer<T> {
fn clone(&self) -> Self {
match self {
Self::Input(input) => Self::Input(input.clone()),
Self::Conclusion(conclusion) => Self::Conclusion(conclusion.clone()),
}
}
}