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)]
12pub enum Value<T: Valueable> {
16 Bool(bool),
18 String(String),
20 Natural(i32),
22 Float(NotNan<f32>),
24 Dict(BTreeMap<String, T>),
26 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), (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), (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), (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)), (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))?)), (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}