use std::iter::Sum;
use crate::diagnostics::Diagnostic;
pub trait ConstantFolding {
type Error;
type T;
fn constant_fold(&mut self) -> Result<(), Self::Error>;
fn constant_folded(mut self) -> Result<Self, Self::Error>
where
Self: Sized,
{
self.constant_fold()?;
Ok(self)
}
fn const_value(&self) -> Option<Self::T> {
None
}
}
impl<T: ConstantFolding> ConstantFolding for Box<T> {
type Error = T::Error;
type T = T::T;
fn constant_fold(&mut self) -> Result<(), Self::Error> {
self.as_mut().constant_fold()
}
fn constant_folded(self) -> Result<Self, Self::Error>
where
Self: Sized,
{
(*self).constant_folded().map(Box::new)
}
fn const_value(&self) -> Option<Self::T> {
self.as_ref().const_value()
}
}
impl<E: ConstantFolding> ConstantFolding for Vec<E> {
type Error = E::Error;
type T = Vec<E::T>;
fn constant_fold(&mut self) -> Result<(), Self::Error> {
self.iter_mut().try_for_each(|e| e.constant_fold())
}
fn const_value(&self) -> Option<Self::T> {
self.iter().map(|e| e.const_value()).collect()
}
}
impl<E: ConstantFolding> ConstantFolding for [E] {
type Error = E::Error;
type T = Vec<E::T>;
fn constant_fold(&mut self) -> Result<(), Self::Error> {
self.iter_mut().try_for_each(|e| e.constant_fold())
}
fn const_value(&self) -> Option<Self::T> {
self.iter().map(|e| e.const_value()).collect()
}
}
pub trait Canonicalize {
fn canonicalize(&mut self);
fn canonicalized(mut self) -> Self
where
Self: Sized,
{
self.canonicalize();
self
}
}
impl<E: Canonicalize> Canonicalize for Vec<E> {
fn canonicalize(&mut self) {
for e in self {
e.canonicalize();
}
}
}
impl<E: Canonicalize> Canonicalize for [E] {
fn canonicalize(&mut self) {
for e in self {
e.canonicalize();
}
}
}
impl<T: Canonicalize> Canonicalize for Box<T> {
fn canonicalize(&mut self) {
self.as_mut().canonicalize()
}
}
pub trait Evaluate<Output> {
fn evaluate(&self) -> Output;
}
impl<O, T: Evaluate<O>> Evaluate<O> for Box<T> {
fn evaluate(&self) -> O {
self.as_ref().evaluate()
}
}
impl<O, T: Evaluate<O>> Evaluate<Option<O>> for Option<T> {
fn evaluate(&self) -> Option<O> {
self.as_ref().map(Evaluate::<O>::evaluate)
}
}
impl<O: Sum, T: Evaluate<O>> Evaluate<O> for [T] {
fn evaluate(&self) -> O {
self.iter().map(Evaluate::<O>::evaluate).sum()
}
}
impl<O: Sum, T: Evaluate<O>> Evaluate<O> for Vec<T> {
fn evaluate(&self) -> O {
self.iter().map(Evaluate::<O>::evaluate).sum()
}
}
pub trait Validatable {
type Diagnostic: Diagnostic;
type Context: ?Sized;
fn validate_with_context(
&self,
context: &Self::Context,
) -> Result<Vec<Self::Diagnostic>, Vec<Self::Diagnostic>>;
fn validate(&self) -> Result<Vec<Self::Diagnostic>, Vec<Self::Diagnostic>>
where
Self::Context: Default,
{
self.validate_with_context(&Default::default())
}
}