Skip to main content

rink_core/runtime/
value.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use super::Substance;
6use crate::loader::Context;
7use crate::parsing::datetime;
8use crate::types::{DateTime, Number};
9use serde_derive::{Deserialize, Serialize};
10use std::ops::{Add, Div, Mul, Neg, Sub};
11
12#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq)]
13pub struct MissingDeps {
14    needed: Vec<String>,
15}
16
17impl MissingDeps {
18    pub fn new(name: &str) -> MissingDeps {
19        MissingDeps {
20            needed: vec![name.into()],
21        }
22    }
23
24    pub fn combine(left: &MissingDeps, right: &MissingDeps) -> MissingDeps {
25        MissingDeps {
26            needed: left
27                .needed
28                .iter()
29                .chain(right.needed.iter())
30                .cloned()
31                .collect(),
32        }
33    }
34
35    pub fn needed(&self) -> &[String] {
36        &self.needed
37    }
38}
39
40impl std::fmt::Display for MissingDeps {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        write!(f, "missing {}", self.needed.join(", "))
43    }
44}
45
46#[derive(Clone, Debug)]
47pub enum Value {
48    Number(Number),
49    DateTime(DateTime),
50    Substance(Substance),
51    MissingDeps(MissingDeps),
52}
53
54pub trait Show {
55    /// Provides a string representation of something, using information contained in a Context.
56    fn show(&self, context: &Context) -> String;
57}
58
59impl Show for DateTime {
60    fn show(&self, context: &Context) -> String {
61        if let Some(h) = context.humanize(self) {
62            format!("{} ({})", self, h)
63        } else {
64            self.to_string()
65        }
66    }
67}
68
69impl Show for Value {
70    fn show(&self, context: &Context) -> String {
71        match *self {
72            Value::Number(ref num) => num.show(context),
73            Value::DateTime(ref dt) => dt.show(context),
74            Value::Substance(ref v) => v.show(context),
75            Value::MissingDeps(ref d) => format!("{d}"),
76        }
77    }
78}
79
80impl Value {
81    pub fn pow(&self, exp: &Value) -> Result<Value, String> {
82        match (self, exp) {
83            (&Value::Number(ref left), &Value::Number(ref right)) => {
84                left.pow(right).map(Value::Number)
85            }
86            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
87                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
88            }
89            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
90                Ok(Value::MissingDeps(a.clone()))
91            }
92            (_, _) => Err("Operation is not defined".to_string()),
93        }
94    }
95
96    pub fn as_number(&self) -> Option<&Number> {
97        if let Value::Number(ref num) = self {
98            Some(num)
99        } else {
100            None
101        }
102    }
103
104    pub fn to_number(&self) -> Option<Number> {
105        if let Value::Number(ref num) = self {
106            Some(num.clone())
107        } else {
108            None
109        }
110    }
111}
112
113impl<'a, 'b> Add<&'b Value> for &'a Value {
114    type Output = Result<Value, String>;
115
116    fn add(self, other: &Value) -> Result<Value, String> {
117        match (self, other) {
118            (&Value::Number(ref left), &Value::Number(ref right)) => (left + right)
119                .ok_or_else(|| {
120                    "Addition of units with mismatched units is not meaningful".to_string()
121                })
122                .map(Value::Number),
123            (&Value::DateTime(ref left), &Value::Number(ref right))
124            | (&Value::Number(ref right), &Value::DateTime(ref left)) => left
125                .checked_add(datetime::to_duration(right)?)
126                .ok_or_else(|| {
127                    "Implementation error: value is out of range representable by datetime"
128                        .to_string()
129                })
130                .map(Value::DateTime),
131            (&Value::Substance(ref left), &Value::Substance(ref right)) => {
132                left.add(right).map(Value::Substance)
133            }
134            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
135                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
136            }
137            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
138                Ok(Value::MissingDeps(a.clone()))
139            }
140            (_, _) => Err("Operation is not defined".to_string()),
141        }
142    }
143}
144
145impl<'a, 'b> Sub<&'b Value> for &'a Value {
146    type Output = Result<Value, String>;
147
148    fn sub(self, other: &Value) -> Result<Value, String> {
149        match (self, other) {
150            (&Value::Number(ref left), &Value::Number(ref right)) => (left - right)
151                .ok_or_else(|| {
152                    "Subtraction of units with mismatched units is not meaningful".to_string()
153                })
154                .map(Value::Number),
155            (&Value::DateTime(ref left), &Value::Number(ref right))
156            | (&Value::Number(ref right), &Value::DateTime(ref left)) => left
157                .checked_sub(datetime::to_duration(right)?)
158                .ok_or_else(|| {
159                    "Implementation error: value is out of range representable by datetime"
160                        .to_string()
161                })
162                .map(Value::DateTime),
163            (&Value::DateTime(ref left), &Value::DateTime(ref right)) => {
164                datetime::from_duration(&(left - right)).map(Value::Number)
165            }
166            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
167                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
168            }
169            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
170                Ok(Value::MissingDeps(a.clone()))
171            }
172            (_, _) => Err("Operation is not defined".to_string()),
173        }
174    }
175}
176
177impl<'a> Neg for &'a Value {
178    type Output = Result<Value, String>;
179
180    fn neg(self) -> Self::Output {
181        match *self {
182            Value::Number(ref num) => (-num)
183                .ok_or_else(|| "Bug: Negation should not fail".to_string())
184                .map(Value::Number),
185            Value::MissingDeps(ref d) => Ok(Value::MissingDeps(d.clone())),
186            _ => Err("Operation is not defined".to_string()),
187        }
188    }
189}
190
191impl<'a, 'b> Mul<&'b Value> for &'a Value {
192    type Output = Result<Value, String>;
193
194    fn mul(self, other: &Value) -> Result<Value, String> {
195        match (self, other) {
196            (&Value::Number(ref left), &Value::Number(ref right)) => (left * right)
197                .ok_or_else(|| "Bug: Mul should not fail".to_string())
198                .map(Value::Number),
199            (&Value::Number(ref co), &Value::Substance(ref sub))
200            | (&Value::Substance(ref sub), &Value::Number(ref co)) => {
201                (sub * co).map(Value::Substance)
202            }
203            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
204                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
205            }
206            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
207                Ok(Value::MissingDeps(a.clone()))
208            }
209            (_, _) => Err("Operation is not defined".to_string()),
210        }
211    }
212}
213
214impl<'a, 'b> Div<&'b Value> for &'a Value {
215    type Output = Result<Value, String>;
216
217    fn div(self, other: &Value) -> Result<Value, String> {
218        match (self, other) {
219            (&Value::Number(ref left), &Value::Number(ref right)) => (left / right)
220                .ok_or_else(|| "Division by zero".to_string())
221                .map(Value::Number),
222            (&Value::Substance(ref sub), &Value::Number(ref co)) => {
223                (sub / co).map(Value::Substance)
224            }
225            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
226                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
227            }
228            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
229                Ok(Value::MissingDeps(a.clone()))
230            }
231            (_, _) => Err("Operation is not defined".to_string()),
232        }
233    }
234}
235
236impl Value {
237    pub fn shl(&self, other: &Value) -> Result<Value, String> {
238        match (self, other) {
239            (&Value::Number(ref left), &Value::Number(ref right)) => {
240                left.shl(right).map(Value::Number)
241            }
242            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
243                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
244            }
245            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
246                Ok(Value::MissingDeps(a.clone()))
247            }
248            (_, _) => Err("Operation is not defined".to_string()),
249        }
250    }
251
252    pub fn shr(&self, other: &Value) -> Result<Value, String> {
253        match (self, other) {
254            (&Value::Number(ref left), &Value::Number(ref right)) => {
255                left.shr(right).map(Value::Number)
256            }
257            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
258                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
259            }
260            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
261                Ok(Value::MissingDeps(a.clone()))
262            }
263            (_, _) => Err("Operation is not defined".to_string()),
264        }
265    }
266
267    pub fn rem(&self, other: &Value) -> Result<Value, String> {
268        match (self, other) {
269            (&Value::Number(ref left), &Value::Number(ref right)) => {
270                left.rem(right).map(Value::Number)
271            }
272            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
273                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
274            }
275            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
276                Ok(Value::MissingDeps(a.clone()))
277            }
278            (_, _) => Err("Operation is not defined".to_string()),
279        }
280    }
281
282    pub fn and(&self, other: &Value) -> Result<Value, String> {
283        match (self, other) {
284            (&Value::Number(ref left), &Value::Number(ref right)) => {
285                left.and(right).map(Value::Number)
286            }
287            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
288                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
289            }
290            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
291                Ok(Value::MissingDeps(a.clone()))
292            }
293            (_, _) => Err("Operation is not defined".to_string()),
294        }
295    }
296
297    pub fn or(&self, other: &Value) -> Result<Value, String> {
298        match (self, other) {
299            (&Value::Number(ref left), &Value::Number(ref right)) => {
300                left.or(right).map(Value::Number)
301            }
302            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
303                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
304            }
305            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
306                Ok(Value::MissingDeps(a.clone()))
307            }
308            (_, _) => Err("Operation is not defined".to_string()),
309        }
310    }
311
312    pub fn xor(&self, other: &Value) -> Result<Value, String> {
313        match (self, other) {
314            (&Value::Number(ref left), &Value::Number(ref right)) => {
315                left.xor(right).map(Value::Number)
316            }
317            (&Value::MissingDeps(ref a), &Value::MissingDeps(ref b)) => {
318                Ok(Value::MissingDeps(MissingDeps::combine(a, b)))
319            }
320            (&Value::MissingDeps(ref a), _) | (_, &Value::MissingDeps(ref a)) => {
321                Ok(Value::MissingDeps(a.clone()))
322            }
323            (_, _) => Err("Operation is not defined".to_string()),
324        }
325    }
326}