1use super::Substance;
6use crate::loader::Context;
7use crate::parsing::datetime;
8use crate::types::{GenericDateTime, Number};
9use chrono::{DateTime, FixedOffset};
10use chrono_tz::Tz;
11use std::ops::{Add, Div, Mul, Neg, Sub};
12
13#[derive(Clone, Debug)]
14pub enum Value {
15 Number(Number),
16 DateTime(GenericDateTime),
17 Substance(Substance),
18}
19
20pub trait Show {
21 fn show(&self, context: &Context) -> String;
23}
24
25impl Show for DateTime<FixedOffset> {
26 fn show(&self, context: &Context) -> String {
27 if let Some(h) = context.humanize(*self) {
28 format!("{} ({})", self, h)
29 } else {
30 self.to_string()
31 }
32 }
33}
34
35impl Show for DateTime<Tz> {
36 fn show(&self, context: &Context) -> String {
37 if let Some(h) = context.humanize(*self) {
38 format!("{} ({})", self, h)
39 } else {
40 self.to_string()
41 }
42 }
43}
44
45impl Show for GenericDateTime {
46 fn show(&self, context: &Context) -> String {
47 match *self {
48 GenericDateTime::Fixed(ref date) => date.show(context),
49 GenericDateTime::Timezone(ref date) => date.show(context),
50 }
51 }
52}
53
54impl Show for Value {
55 fn show(&self, context: &Context) -> String {
56 match *self {
57 Value::Number(ref num) => num.show(context),
58 Value::DateTime(ref dt) => dt.show(context),
59 Value::Substance(ref v) => v.show(context),
60 }
61 }
62}
63
64impl Value {
65 pub fn pow(&self, exp: &Value) -> Result<Value, String> {
66 match (self, exp) {
67 (&Value::Number(ref left), &Value::Number(ref right)) => {
68 left.pow(right).map(Value::Number)
69 }
70 (_, _) => Err("Operation is not defined".to_string()),
71 }
72 }
73}
74
75impl<'a, 'b> Add<&'b Value> for &'a Value {
76 type Output = Result<Value, String>;
77
78 fn add(self, other: &Value) -> Result<Value, String> {
79 match (self, other) {
80 (&Value::Number(ref left), &Value::Number(ref right)) => (left + right)
81 .ok_or_else(|| {
82 "Addition of units with mismatched units is not meaningful".to_string()
83 })
84 .map(Value::Number),
85 (&Value::DateTime(ref left), &Value::Number(ref right))
86 | (&Value::Number(ref right), &Value::DateTime(ref left)) => match *left {
87 GenericDateTime::Fixed(left) => left
88 .checked_add_signed(datetime::to_duration(right)?)
89 .map(GenericDateTime::Fixed),
90 GenericDateTime::Timezone(left) => left
91 .checked_add_signed(datetime::to_duration(right)?)
92 .map(GenericDateTime::Timezone),
93 }
94 .ok_or_else(|| {
95 "Implementation error: value is out of range representable by datetime".to_string()
96 })
97 .map(Value::DateTime),
98 (&Value::Substance(ref left), &Value::Substance(ref right)) => {
99 left.add(right).map(Value::Substance)
100 }
101 (_, _) => Err("Operation is not defined".to_string()),
102 }
103 }
104}
105
106impl<'a, 'b> Sub<&'b Value> for &'a Value {
107 type Output = Result<Value, String>;
108
109 fn sub(self, other: &Value) -> Result<Value, String> {
110 match (self, other) {
111 (&Value::Number(ref left), &Value::Number(ref right)) => (left - right)
112 .ok_or_else(|| {
113 "Subtraction of units with mismatched units is not meaningful".to_string()
114 })
115 .map(Value::Number),
116 (&Value::DateTime(ref left), &Value::Number(ref right))
117 | (&Value::Number(ref right), &Value::DateTime(ref left)) => match *left {
118 GenericDateTime::Fixed(left) => left
119 .checked_sub_signed(datetime::to_duration(right)?)
120 .map(GenericDateTime::Fixed),
121 GenericDateTime::Timezone(left) => left
122 .checked_sub_signed(datetime::to_duration(right)?)
123 .map(GenericDateTime::Timezone),
124 }
125 .ok_or_else(|| {
126 "Implementation error: value is out of range representable by datetime".to_string()
127 })
128 .map(Value::DateTime),
129 (&Value::DateTime(ref left), &Value::DateTime(ref right)) => {
130 datetime::from_duration(&match (left, right) {
131 (&GenericDateTime::Fixed(ref left), &GenericDateTime::Fixed(ref right)) => {
132 *left - *right
133 }
134 (&GenericDateTime::Fixed(ref left), &GenericDateTime::Timezone(ref right)) => {
135 *left - right.with_timezone(left.offset())
136 }
137 (
138 &GenericDateTime::Timezone(ref left),
139 &GenericDateTime::Timezone(ref right),
140 ) => *left - *right,
141 (&GenericDateTime::Timezone(ref left), &GenericDateTime::Fixed(ref right)) => {
142 left.with_timezone(right.offset()) - *right
143 }
144 })
145 .map(Value::Number)
146 }
147 (_, _) => Err("Operation is not defined".to_string()),
148 }
149 }
150}
151
152impl<'a> Neg for &'a Value {
153 type Output = Result<Value, String>;
154
155 fn neg(self) -> Self::Output {
156 match *self {
157 Value::Number(ref num) => (-num)
158 .ok_or_else(|| "Bug: Negation should not fail".to_string())
159 .map(Value::Number),
160 _ => Err("Operation is not defined".to_string()),
161 }
162 }
163}
164
165impl<'a, 'b> Mul<&'b Value> for &'a Value {
166 type Output = Result<Value, String>;
167
168 fn mul(self, other: &Value) -> Result<Value, String> {
169 match (self, other) {
170 (&Value::Number(ref left), &Value::Number(ref right)) => (left * right)
171 .ok_or_else(|| "Bug: Mul should not fail".to_string())
172 .map(Value::Number),
173 (&Value::Number(ref co), &Value::Substance(ref sub))
174 | (&Value::Substance(ref sub), &Value::Number(ref co)) => {
175 (sub * co).map(Value::Substance)
176 }
177 (_, _) => Err("Operation is not defined".to_string()),
178 }
179 }
180}
181
182impl<'a, 'b> Div<&'b Value> for &'a Value {
183 type Output = Result<Value, String>;
184
185 fn div(self, other: &Value) -> Result<Value, String> {
186 match (self, other) {
187 (&Value::Number(ref left), &Value::Number(ref right)) => (left / right)
188 .ok_or_else(|| "Division by zero".to_string())
189 .map(Value::Number),
190 (&Value::Substance(ref sub), &Value::Number(ref co)) => {
191 (sub / co).map(Value::Substance)
192 }
193 (_, _) => Err("Operation is not defined".to_string()),
194 }
195 }
196}
197
198impl Value {
199 pub fn shl(&self, other: &Value) -> Result<Value, String> {
200 match (self, other) {
201 (&Value::Number(ref left), &Value::Number(ref right)) => {
202 left.shl(right).map(Value::Number)
203 }
204 (_, _) => Err("Operation is not defined".to_string()),
205 }
206 }
207
208 pub fn shr(&self, other: &Value) -> Result<Value, String> {
209 match (self, other) {
210 (&Value::Number(ref left), &Value::Number(ref right)) => {
211 left.shr(right).map(Value::Number)
212 }
213 (_, _) => Err("Operation is not defined".to_string()),
214 }
215 }
216
217 pub fn rem(&self, other: &Value) -> Result<Value, String> {
218 match (self, other) {
219 (&Value::Number(ref left), &Value::Number(ref right)) => {
220 left.rem(right).map(Value::Number)
221 }
222 (_, _) => Err("Operation is not defined".to_string()),
223 }
224 }
225
226 pub fn and(&self, other: &Value) -> Result<Value, String> {
227 match (self, other) {
228 (&Value::Number(ref left), &Value::Number(ref right)) => {
229 left.and(right).map(Value::Number)
230 }
231 (_, _) => Err("Operation is not defined".to_string()),
232 }
233 }
234
235 pub fn or(&self, other: &Value) -> Result<Value, String> {
236 match (self, other) {
237 (&Value::Number(ref left), &Value::Number(ref right)) => {
238 left.or(right).map(Value::Number)
239 }
240 (_, _) => Err("Operation is not defined".to_string()),
241 }
242 }
243
244 pub fn xor(&self, other: &Value) -> Result<Value, String> {
245 match (self, other) {
246 (&Value::Number(ref left), &Value::Number(ref right)) => {
247 left.xor(right).map(Value::Number)
248 }
249 (_, _) => Err("Operation is not defined".to_string()),
250 }
251 }
252}