use super::Substance;
use crate::loader::Context;
use crate::parsing::datetime;
use crate::types::{DateTime, Number};
use serde_derive::{Deserialize, Serialize};
use std::ops::{Add, Div, Mul, Neg, Sub};
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq)]
pub struct MissingDeps {
needed: Vec<String>,
}
impl MissingDeps {
pub fn new(name: &str) -> MissingDeps {
MissingDeps {
needed: vec![name.into()],
}
}
pub fn combine(left: &MissingDeps, right: &MissingDeps) -> MissingDeps {
MissingDeps {
needed: left
.needed
.iter()
.chain(right.needed.iter())
.cloned()
.collect(),
}
}
pub fn needed(&self) -> &[String] {
&self.needed
}
}
impl std::fmt::Display for MissingDeps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "missing {}", self.needed.join(", "))
}
}
#[derive(Clone, Debug)]
pub enum Value {
Number(Number),
DateTime(DateTime),
Substance(Substance),
MissingDeps(MissingDeps),
}
pub trait Show {
fn show(&self, context: &Context) -> String;
}
impl Show for DateTime {
fn show(&self, context: &Context) -> String {
if let Some(h) = context.humanize(self) {
format!("{} ({})", self, h)
} else {
self.to_string()
}
}
}
impl Show for Value {
fn show(&self, context: &Context) -> String {
match *self {
Value::Number(ref num) => num.show(context),
Value::DateTime(ref dt) => dt.show(context),
Value::Substance(ref v) => v.show(context),
Value::MissingDeps(ref d) => format!("{d}"),
}
}
}
impl Value {
pub fn pow(&self, exp: &Value) -> Result<Value, String> {
match (self, exp) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.pow(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
pub fn as_number(&self) -> Option<&Number> {
if let Value::Number(ref num) = self {
Some(num)
} else {
None
}
}
pub fn to_number(&self) -> Option<Number> {
if let Value::Number(ref num) = self {
Some(num.clone())
} else {
None
}
}
}
impl<'a, 'b> Add<&'b Value> for &'a Value {
type Output = Result<Value, String>;
fn add(self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => (left + right)
.ok_or_else(|| {
"Addition of units with mismatched units is not meaningful".to_string()
})
.map(Value::Number),
(&Value::DateTime(ref left), &Value::Number(ref right))
| (&Value::Number(ref right), &Value::DateTime(ref left)) => left
.checked_add(datetime::to_duration(right)?)
.ok_or_else(|| {
"Implementation error: value is out of range representable by datetime"
.to_string()
})
.map(Value::DateTime),
(&Value::Substance(ref left), &Value::Substance(ref right)) => {
left.add(right).map(Value::Substance)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
}
impl<'a, 'b> Sub<&'b Value> for &'a Value {
type Output = Result<Value, String>;
fn sub(self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => (left - right)
.ok_or_else(|| {
"Subtraction of units with mismatched units is not meaningful".to_string()
})
.map(Value::Number),
(&Value::DateTime(ref left), &Value::Number(ref right))
| (&Value::Number(ref right), &Value::DateTime(ref left)) => left
.checked_sub(datetime::to_duration(right)?)
.ok_or_else(|| {
"Implementation error: value is out of range representable by datetime"
.to_string()
})
.map(Value::DateTime),
(&Value::DateTime(ref left), &Value::DateTime(ref right)) => {
datetime::from_duration(&(left - right)).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
}
impl<'a> Neg for &'a Value {
type Output = Result<Value, String>;
fn neg(self) -> Self::Output {
match *self {
Value::Number(ref num) => (-num)
.ok_or_else(|| "Bug: Negation should not fail".to_string())
.map(Value::Number),
Value::MissingDeps(ref d) => Ok(Value::MissingDeps(d.clone())),
_ => Err("Operation is not defined".to_string()),
}
}
}
impl<'a, 'b> Mul<&'b Value> for &'a Value {
type Output = Result<Value, String>;
fn mul(self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => (left * right)
.ok_or_else(|| "Bug: Mul should not fail".to_string())
.map(Value::Number),
(&Value::Number(ref co), &Value::Substance(ref sub))
| (&Value::Substance(ref sub), &Value::Number(ref co)) => {
(sub * co).map(Value::Substance)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
}
impl<'a, 'b> Div<&'b Value> for &'a Value {
type Output = Result<Value, String>;
fn div(self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => (left / right)
.ok_or_else(|| "Division by zero".to_string())
.map(Value::Number),
(&Value::Substance(ref sub), &Value::Number(ref co)) => {
(sub / co).map(Value::Substance)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
}
impl Value {
pub fn shl(&self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.shl(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
pub fn shr(&self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.shr(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
pub fn rem(&self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.rem(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
pub fn and(&self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.and(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
pub fn or(&self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.or(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
pub fn xor(&self, other: &Value) -> Result<Value, String> {
match (self, other) {
(&Value::Number(ref left), &Value::Number(ref right)) => {
left.xor(right).map(Value::Number)
}
(&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
}
(&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
Ok(Value::MissingDeps(a.clone()))
}
(_, _) => Err("Operation is not defined".to_string()),
}
}
}