diff --git a/src/bin.rs b/src/bin.rs index df8a4b8..21579b6 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -8,6 +8,7 @@ use renderer::compile_template; use renderer::CompileError; use renderer::ContextElement; use renderer::DustRenderer; +use renderer::IceResult; use renderer::IntoContextElement; use renderer::Loopable; use renderer::RenderError; @@ -387,6 +388,10 @@ impl CompareContextElement for serde_json::Value { _ => panic!("Unimplemented comparison type."), } } + + fn math_add<'a>(&self, other: &dyn ContextElement) -> Option> { + todo!() + } } #[derive(Debug)] diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index a83ca52..5ef6e3c 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -4,6 +4,7 @@ use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; use crate::renderer::DustRenderer; use std::any::Any; +use std::ops::Add; use std::rc::Rc; use std::{cmp::Ordering, fmt::Debug}; @@ -61,6 +62,8 @@ pub trait CompareContextElement: CastToAny { fn equals(&self, other: &dyn ContextElement) -> bool; fn partial_compare(&self, other: &dyn ContextElement) -> Option; + + fn math_add<'a>(&self, other: &dyn ContextElement) -> Option>; } impl CastToAny for C { @@ -81,6 +84,14 @@ impl<'a, 'b> PartialOrd<&'b dyn ContextElement> for &'a dyn ContextElement { } } +impl<'a> Add<&'a dyn ContextElement> for &'a dyn ContextElement { + type Output = Option>; + + fn add(self, other: &'a dyn ContextElement) -> Self::Output { + self.math_add(other) + } +} + pub trait FromContextElement { fn from_context_element(&self) -> &dyn IntoContextElement; } @@ -91,7 +102,7 @@ impl FromContextElement for C { } } -pub trait IntoContextElement: Debug + Walkable /* + CloneIntoBoxedContextElement*/ { +pub trait IntoContextElement: Debug + Walkable { fn into_context_element<'a>( &'a self, renderer: &DustRenderer, diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 288b2ab..434dedd 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -12,6 +12,7 @@ mod walking; pub use context_element::CompareContextElement; pub use context_element::ContextElement; +pub use context_element::IceResult; pub use context_element::IntoContextElement; pub use context_element::Loopable; pub use context_element::Renderable; diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 0008ac5..5a6f80b 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -18,6 +18,7 @@ use crate::renderer::Walkable; use std::borrow::Borrow; use std::cmp::Ordering; use std::collections::HashMap; +use std::convert::TryInto; #[derive(Debug)] pub struct ParametersContext<'a> { @@ -325,4 +326,93 @@ impl CompareContextElement for OwnedLiteral { }, } } + + fn math_add<'a>(&self, other: &dyn ContextElement) -> Option> { + // If its an OwnedLiteral then add them directly, otherwise + // defer to the other type's implementation of + // CompareContextElement since the end user could add any + // type. + match other.to_any().downcast_ref::() { + None => other.math_add(self), + Some(other_literal) => { + match (self, other_literal) { + (OwnedLiteral::LString(_), _) | (_, OwnedLiteral::LString(_)) => None, + ( + OwnedLiteral::LPositiveInteger(self_num), + OwnedLiteral::LPositiveInteger(other_num), + ) => math_ints(*self_num, *other_num, std::ops::Add::add) + .map(IceResult::from_owned), + ( + OwnedLiteral::LNegativeInteger(self_num), + OwnedLiteral::LNegativeInteger(other_num), + ) => math_ints(*self_num, *other_num, std::ops::Add::add) + .map(IceResult::from_owned), + ( + OwnedLiteral::LPositiveInteger(self_num), + OwnedLiteral::LNegativeInteger(other_num), + ) => math_ints(*self_num, *other_num, std::ops::Add::add) + .map(IceResult::from_owned), + ( + OwnedLiteral::LNegativeInteger(self_num), + OwnedLiteral::LPositiveInteger(other_num), + ) => math_ints(*self_num, *other_num, std::ops::Add::add) + .map(IceResult::from_owned), + (OwnedLiteral::LFloat(self_num), OwnedLiteral::LFloat(other_num)) => Some( + IceResult::from_owned(OwnedLiteral::LFloat(self_num + other_num)), + ), + (OwnedLiteral::LFloat(self_num), OwnedLiteral::LPositiveInteger(other_num)) => { + Some(IceResult::from_owned(OwnedLiteral::LFloat( + self_num + (*other_num as f64), + ))) + } + (OwnedLiteral::LPositiveInteger(self_num), OwnedLiteral::LFloat(other_num)) => { + Some(IceResult::from_owned(OwnedLiteral::LFloat( + (*self_num as f64) + other_num, + ))) + } + (OwnedLiteral::LFloat(self_num), OwnedLiteral::LNegativeInteger(other_num)) => { + Some(IceResult::from_owned(OwnedLiteral::LFloat( + self_num + (*other_num as f64), + ))) + } + (OwnedLiteral::LNegativeInteger(self_num), OwnedLiteral::LFloat(other_num)) => { + Some(IceResult::from_owned(OwnedLiteral::LFloat( + (*self_num as f64) + other_num, + ))) + } + } + } + } + } } + +/// For math operations that take in integers and return integers +/// (add, subtract, multiply) +fn math_ints(left: L, right: R, operation: F) -> Option +where + L: Into, + R: Into, + F: Fn(i128, i128) -> i128, +{ + let result = operation(left.into(), right.into()); + std::convert::TryInto::::try_into(result) + .map(OwnedLiteral::LPositiveInteger) + .ok() + .or(std::convert::TryInto::::try_into(result) + .map(OwnedLiteral::LNegativeInteger) + .ok()) +} + +// /// For math operations that take in integers and return integers +// /// (add, subtract, multiply) +// fn math_floats(left: L, right: R, operation: F) -> Option +// where +// L: Into, +// R: Into, +// F: Fn(f64, f64) -> f64, +// { +// let result = operation(left.into(), right.into()); +// std::convert::TryInto::::try_into(result) +// .map(OwnedLiteral::LFloat) +// .ok() +// }