wagon_value/
value.rs

1
2use std::collections::BTreeMap;
3use std::fmt::Display;
4use std::ops::{Add, Sub, Mul, Div, Not, Rem};
5use ordered_float::NotNan;
6
7pub use num_traits::Pow;
8
9use crate::{ValueError, ValueResult, Valueable};
10
11#[derive(Debug, Eq, PartialEq, Hash, Clone)]
12/// The most basic types that a value can ever be.
13///
14/// For recursion reasons, this type is generic over any other type that can be seen as a Value (see [`Valueable`]).
15pub enum Value<T: Valueable> {
16    /// A bool.
17    Bool(bool),
18    /// A string.
19    String(String),
20    /// A whole number.
21    Natural(i32),
22    /// A float.
23    Float(NotNan<f32>),
24    /// A dictionary.
25    Dict(BTreeMap<String, T>),
26    /// A list.
27    Array(Vec<T>)
28}
29
30impl<T: Valueable> Valueable for Value<T> {
31    fn is_truthy(&self) -> ValueResult<bool, Self> {
32        Ok(match self {
33            Self::Bool(b) => *b,
34            Self::String(s) => !s.is_empty(),
35            Self::Natural(n) => n > &0,
36            Self::Float(f) => !f.eq(&0.0),
37            Self::Dict(m) => !m.is_empty(),
38            Self::Array(a) => !a.is_empty(),
39        })
40    }
41
42    #[allow(clippy::cast_possible_truncation)]
43    fn to_int(&self) -> ValueResult<i32, Self> {
44        Ok(match self {
45            Self::Natural(n) => *n,
46            Self::Float(f) => f.round() as i32,
47            o => i32::from(o.is_truthy()?)
48        })
49    }
50
51    fn to_float(&self) -> ValueResult<f32, Self> {
52        Ok(match self {
53            Self::Natural(n) => *n as f32,
54            Self::Float(f) => f.into_inner(),
55            o => if o.is_truthy()? { 1.0 } else { 0.0 }
56        })
57    }
58
59    fn display_numerical(&self) -> ValueResult<String, Self> {
60        Ok(match self {
61            Self::Float(f) => f.to_string(),
62            other => other.to_int()?.to_string()
63        })
64    }
65}
66
67impl<T: Valueable> Display for Value<T> {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        match self {
70            Self::Bool(v) => write!(f, "{v}"),
71            Self::String(v) => write!(f, "{v}"),
72            Self::Natural(v) => write!(f, "{v}"),
73            Self::Float(v) => write!(f, "{v}"),
74            Self::Dict(v) => write!(f, "{v:?}"),
75            Self::Array(v) => write!(f, "{v:?}"),
76        }
77    }
78}
79
80impl<T: Valueable> From<Value<T>> for i32 {
81    fn from(value: Value<T>) -> Self {
82        #[allow(clippy::expect_used)]
83        value.to_int().expect("This conversion can not fail")
84    }
85}
86
87impl<T: Valueable> From<Value<T>> for f32 {
88    fn from(value: Value<T>) -> Self {
89        #[allow(clippy::expect_used)]
90        value.to_float().expect("This conversion can not fail")
91    }
92}
93
94impl<T: Valueable> From<Value<T>> for bool {
95    fn from(value: Value<T>) -> Self {
96        #[allow(clippy::expect_used)]
97        value.is_truthy().expect("This conversion can not fail")
98    }
99}
100
101impl<T: Valueable> From<bool> for Value<T> {
102    fn from(value: bool) -> Self {
103        Self::Bool(value)
104    }
105}
106
107impl<T: Valueable> From<String> for Value<T> {
108    fn from(value: String) -> Self {
109        Self::String(value)
110    }
111}
112
113impl<T: Valueable> From<&str> for Value<T> {
114    fn from(value: &str) -> Self {
115        Self::String(String::from(value))
116    }
117}
118
119impl<T: Valueable> From<i32> for Value<T> {
120    fn from(value: i32) -> Self {
121        Self::Natural(value)
122    }
123}
124
125impl<T: Valueable> TryFrom<f32> for Value<T> {
126    type Error = ValueError<Self>;
127
128    fn try_from(value: f32) -> Result<Self, Self::Error> {
129        Ok(Self::Float(NotNan::try_from(value)?))
130    }
131}
132
133impl<T: Valueable> From<BTreeMap<String, T>> for Value<T> {
134    fn from(value: BTreeMap<String, T>) -> Self {
135        Self::Dict(value)
136    }
137}
138
139impl<T: Valueable> From<Vec<T>> for Value<T> {
140    fn from(value: Vec<T>) -> Self {
141        Self::Array(value)
142    }
143}
144
145impl<T: Valueable> Add for Value<T> {
146    type Output = ValueResult<Self, Self>;
147
148    fn add(self, rhs: Self) -> Self::Output {
149        Ok(match (self, rhs) {
150            (Self::Bool(b1), Self::Bool(b2)) => Self::Bool(b1 || b2), // or
151            (Self::Bool(b), Self::Natural(i)) | (Self::Natural(i), Self::Bool(b)) => Self::Natural(i32::from(b) + i),
152            (Self::Bool(b), Self::Float(f)) | (Self::Float(f), Self::Bool(b)) => Self::Float(NotNan::new(f32::from(u8::from(b)))? + f),
153            (Self::String(s1), Self::String(s2)) => Self::String(s1.add(&s2)),
154            (Self::Natural(i1), Self::Natural(i2)) => Self::Natural(i1 + i2),
155            (Self::Natural(i), Self::Float(f)) | (Self::Float(f), Self::Natural(i)) => Self::Float(NotNan::new(i as f32)? + f),
156            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 + f2),
157            (Self::Dict(d1), Self::Dict(d2)) => Self::Dict(d1.into_iter().chain(d2).collect()),
158            (Self::Array(a1), Self::Array(a2)) => Self::Array(a1.into_iter().chain(a2).collect()),
159            (v1, v2) => return Err(ValueError::OperationError(v1, v2, "+".to_owned()))
160        })
161    }
162}
163
164impl<T: Valueable> Sub for Value<T> {
165    type Output = ValueResult<Self, Self>;
166
167    fn sub(self, rhs: Self) -> Self::Output {
168        Ok(match (self, rhs) {
169            (Self::Bool(b1), Self::Bool(b2)) => Self::Bool(b1 && !b2), // nand
170            (Self::Bool(b), Self::Natural(i)) | (Self::Natural(i), Self::Bool(b)) => Self::Natural(i32::from(b) - i),
171            (Self::Bool(b), Self::Float(f)) | (Self::Float(f), Self::Bool(b)) => Self::Float(NotNan::new(f32::from(u8::from(b)))? - f),
172            (Self::Natural(i1), Self::Natural(i2)) => Self::Natural(i1 - i2),
173            (Self::Natural(i), Self::Float(f)) | (Self::Float(f), Self::Natural(i)) => Self::Float(NotNan::new(i as f32)? - f),
174            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 - f2),
175            (Self::Array(a1), Self::Array(a2)) => Self::Array(a1.into_iter().filter(|x| !a2.contains(x)).collect()),
176            (v1, v2) => return Err(ValueError::OperationError(v1, v2, "-".to_owned()))
177        })
178    }
179}
180
181impl<T: Valueable> Mul for Value<T> {
182    type Output = ValueResult<Self, Self>;
183
184    fn mul(self, rhs: Self) -> Self::Output {
185        Ok(match (self, rhs) {
186            (Self::Bool(b1), Self::Bool(b2)) => Self::Bool(b1 && b2), // and
187            (Self::Bool(b), Self::Natural(i)) | (Self::Natural(i), Self::Bool(b)) => Self::Natural(i32::from(b) * i),
188            (Self::Bool(b), Self::Float(f)) | (Self::Float(f), Self::Bool(b)) => Self::Float(NotNan::new(f32::from(u8::from(b)))? * f),
189            (Self::Natural(i1), Self::Natural(i2)) => Self::Natural(i1 * i2),
190            (Self::Natural(i), Self::Float(f)) | (Self::Float(f), Self::Natural(i)) => Self::Float(NotNan::new(i as f32)? * f),
191            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 * f2),
192            (v1, v2) => return Err(ValueError::OperationError(v1, v2, "*".to_owned()))
193        })
194    }
195}
196
197impl<T: Valueable> Div for Value<T> {
198    type Output = ValueResult<Self, Self>;
199
200    fn div(self, rhs: Self) -> Self::Output {
201        Ok(match (self, rhs) {
202            (Self::Bool(b1), Self::Bool(b2)) => Self::Bool((b1 || b2) && !(b1 && b2)), // xor
203            (Self::Bool(b), Self::Natural(i)) => Self::Natural(i32::from(b) / i), 
204            (Self::Natural(i), Self::Bool(b)) => Self::Natural(i / i32::from(b)),
205            (Self::Bool(b), Self::Float(f)) => Self::Float(NotNan::new(f32::from(u8::from(b)))? / f),
206            (Self::Float(f), Self::Bool(b)) => Self::Float(f / NotNan::new(f32::from(u8::from(b)))?),
207
208            (Self::Natural(i1), Self::Natural(i2)) => Self::Natural(i1 / i2),
209            (Self::Natural(i), Self::Float(f)) => Self::Float(NotNan::new(i as f32)? / f),
210            (Self::Float(f), Self::Natural(i)) => Self::Float(f / NotNan::new(i as f32)?),
211
212            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 / f2),
213            (v1, v2) => return Err(ValueError::OperationError(v1, v2, "/".to_owned()))
214        })
215    }
216}
217
218impl<T: Valueable> Not for Value<T> {
219    type Output = ValueResult<Self, Self>;
220
221    fn not(self) -> Self::Output {
222        match self {
223            Self::Bool(b) => Ok(Self::Bool(!b)),
224            v => Err(ValueError::NegationError(v))
225        }
226    }
227}
228
229impl<T: Valueable> Rem for Value<T> {
230    type Output = ValueResult<Self, Self>;
231
232    fn rem(self, rhs: Self) -> Self::Output {
233        Ok(match (self, rhs) {
234            (Self::Bool(b), Self::Natural(i)) => Self::Natural(i32::from(b) % i), 
235            (Self::Natural(i), Self::Bool(b)) => Self::Natural(i % i32::from(b)),
236            (Self::Bool(b), Self::Float(f)) => Self::Float(NotNan::new(f32::from(u8::from(b)))? % f),
237            (Self::Float(f), Self::Bool(b)) => Self::Float(f % NotNan::new(f32::from(u8::from(b)))?),
238
239            (Self::Natural(i1), Self::Natural(i2)) => Self::Natural(i1 % i2),
240            (Self::Natural(i), Self::Float(f)) => Self::Float(NotNan::new(i as f32)? % f),
241            (Self::Float(f), Self::Natural(i)) => Self::Float(f % NotNan::new(i as f32)?),
242
243            (Self::Float(f1), Self::Float(f2)) => Self::Float(f1 % f2),
244            (v1, v2) => return Err(ValueError::OperationError(v1, v2, "%".to_owned()))
245        })
246    }
247}
248
249impl<T: Valueable> Pow<Self> for Value<T> {
250    type Output = ValueResult<Self, Self>;
251
252    #[allow(clippy::cast_sign_loss)]
253    fn pow(self, rhs: Self) -> Self::Output { 
254        match (self, rhs) {
255            (Self::Bool(true), Self::Natural(_)) | (Self::Natural(_), Self::Bool(false)) => Ok(Self::Natural(1)),
256            (Self::Bool(false), Self::Natural(_)) => Ok(Self::Natural(0)),
257            (Self::Natural(i), Self::Bool(true)) => Ok(Self::Natural(i)),
258            (Self::Bool(true), Self::Float(_)) | (Self::Float(_), Self::Bool(false)) => Ok(Self::Float(NotNan::new(1.0)?)),
259            (Self::Bool(false), Self::Float(_)) => Ok(Self::Float(NotNan::new(0.0)?)),
260            (Self::Float(f), Self::Bool(true)) => Ok(Self::Float(f)),
261            (Self::Natural(i1), Self::Natural(i2)) if i2 >= 0 => Ok(Self::Natural((i1).pow((i2).try_into()?))),
262            (Self::Natural(i1), Self::Natural(i2)) => Ok(Self::Float(NotNan::new(1.0 / (i1.pow((-i2) as u32) as f32))?)), // Power of negative number is division
263            (Self::Natural(i), Self::Float(f)) => Ok(Self::Float(NotNan::new(i as f32)?.pow(f))),
264            (Self::Float(f), Self::Natural(i)) => Ok(Self::Float(f.pow(i))),
265            (Self::Float(f1), Self::Float(f2)) => Ok(Self::Float(f1.pow(f2))),
266            (v1, v2) => Err(ValueError::OperationError(v1, v2, "**".to_owned()))
267        }
268    }
269}
270
271impl<T: Valueable> PartialOrd for Value<T> {
272    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
273        match (self, other) {
274            (Self::String(s1), Self::String(s2)) => s1.partial_cmp(s2),
275            (Self::Natural(i1), Self::Natural(i2)) => i1.partial_cmp(i2),
276            (Self::Float(f1), Self::Float(f2)) => f1.partial_cmp(f2),
277            (Self::Bool(b1), Self::Bool(b2)) => b1.partial_cmp(b2),
278            (Self::Bool(b), Self::Natural(i)) => {
279                if *b {
280                    1.partial_cmp(i)
281                } else {
282                    0.partial_cmp(i)
283                }
284            },
285            (Self::Natural(i), Self::Bool(b)) => {
286                if *b {
287                    i.partial_cmp(&1)
288                } else {
289                    i.partial_cmp(&0)
290                }
291            },
292            (Self::Bool(b), Self::Float(f)) => {
293                let bool_float: NotNan<f32> = NotNan::from(i8::from(*b));
294                bool_float.partial_cmp(f)
295            },
296            (Self::Float(f), Self::Bool(b)) => {
297                let bool_float: NotNan<f32> = NotNan::from(i8::from(*b));
298                f.partial_cmp(&bool_float)
299            },
300            (_, _) => None
301        }
302    }
303}