1use crate::traits::structural_eq::StructuralEq;
2use crate::traits::value_eq::ValueEq;
3use crate::types::type_container::TypeContainer;
4use crate::values::core_value::CoreValue;
5use crate::values::core_values::integer::typed_integer::TypedInteger;
6use crate::values::value_container::ValueError;
7use log::error;
8use std::fmt::{Display, Formatter};
9use std::ops::{Add, AddAssign, Deref, Neg, Not, Sub};
10
11#[derive(Clone, Debug, Eq, PartialEq, Hash)]
12pub struct Value {
13 pub inner: CoreValue,
14 pub actual_type: Box<TypeContainer>,
15}
16
17impl StructuralEq for Value {
20 fn structural_eq(&self, other: &Self) -> bool {
21 self.inner.structural_eq(&other.inner)
22 }
23}
24
25impl ValueEq for Value {
28 fn value_eq(&self, other: &Self) -> bool {
29 self == other
30 }
31}
32
33impl Deref for Value {
34 type Target = CoreValue;
35
36 fn deref(&self) -> &Self::Target {
37 &self.inner
38 }
39}
40
41impl<T: Into<CoreValue>> From<T> for Value {
42 fn from(inner: T) -> Self {
43 let inner = inner.into();
44 let new_type = inner.default_type();
45 Value {
46 inner,
47 actual_type: Box::new(new_type),
48 }
49 }
50}
51impl Value {
52 pub fn null() -> Self {
53 CoreValue::Null.into()
54 }
55}
56
57impl Value {
58 pub fn is_type(&self) -> bool {
59 matches!(self.inner, CoreValue::Type(_))
60 }
61 pub fn is_null(&self) -> bool {
62 matches!(self.inner, CoreValue::Null)
63 }
64 pub fn is_text(&self) -> bool {
65 matches!(self.inner, CoreValue::Text(_))
66 }
67 pub fn is_integer_i8(&self) -> bool {
68 matches!(&self.inner, CoreValue::TypedInteger(TypedInteger::I8(_)))
69 }
70 pub fn is_bool(&self) -> bool {
71 matches!(self.inner, CoreValue::Boolean(_))
72 }
73 pub fn is_map(&self) -> bool {
74 matches!(self.inner, CoreValue::Map(_))
75 }
76 pub fn is_list(&self) -> bool {
77 matches!(self.inner, CoreValue::List(_))
78 }
79 pub fn actual_type(&self) -> &TypeContainer {
80 self.actual_type.as_ref()
81 }
82}
83
84impl Add for Value {
85 type Output = Result<Value, ValueError>;
86 fn add(self, rhs: Value) -> Self::Output {
87 Ok((&self.inner + &rhs.inner)?.into())
88 }
89}
90
91impl Add for &Value {
92 type Output = Result<Value, ValueError>;
93 fn add(self, rhs: &Value) -> Self::Output {
94 Value::add(self.clone(), rhs.clone())
95 }
96}
97
98impl Sub for Value {
99 type Output = Result<Value, ValueError>;
100 fn sub(self, rhs: Value) -> Self::Output {
101 Ok((&self.inner - &rhs.inner)?.into())
102 }
103}
104
105impl Sub for &Value {
106 type Output = Result<Value, ValueError>;
107 fn sub(self, rhs: &Value) -> Self::Output {
108 Value::sub(self.clone(), rhs.clone())
109 }
110}
111
112impl Neg for Value {
113 type Output = Result<Value, ValueError>;
114
115 fn neg(self) -> Self::Output {
116 (-self.inner).map(Value::from)
117 }
118}
119
120impl Not for Value {
121 type Output = Option<Value>;
122
123 fn not(self) -> Self::Output {
124 (!self.inner).map(Value::from)
125 }
126}
127
128impl<T> AddAssign<T> for Value
130where
131 Value: From<T>,
132{
133 fn add_assign(&mut self, rhs: T) {
134 let rhs: Value = rhs.into();
135 let res = self.inner.clone() + rhs.inner;
136 if let Ok(res) = res {
137 self.inner = res;
138 } else {
139 error!("Failed to add value: {res:?}");
140 }
141 }
142}
143
144impl Display for Value {
145 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
146 write!(f, "{}", self.inner)
147 }
148}
149
150impl<T> From<Option<T>> for Value
151where
152 T: Into<Value>,
153{
154 fn from(opt: Option<T>) -> Self {
155 match opt {
156 Some(v) => v.into(),
157 None => Value::null(),
158 }
159 }
160}
161
162#[cfg(test)]
163mod tests {
167 use super::*;
168 use crate::{
169 assert_structural_eq, datex_list,
170 logger::init_logger_debug,
171 values::core_values::{
172 endpoint::Endpoint,
173 integer::{Integer, typed_integer::TypedInteger},
174 list::List,
175 },
176 };
177 use log::{debug, info};
178 use std::str::FromStr;
179
180 #[test]
181 fn endpoint() {
182 init_logger_debug();
183 let endpoint = Value::from(Endpoint::from_str("@test").unwrap());
184 assert_eq!(endpoint.to_string(), "@test");
185 }
186
187 #[test]
188 fn new_addition_assignments() {
189 let mut x = Value::from(42i8);
190 let y = Value::from(27i8);
191
192 x += y.clone();
193 assert_eq!(x, Value::from(69i8));
194 }
195
196 #[test]
197 fn new_additions() {
198 let x = Value::from(42i8);
199 let y = Value::from(27i8);
200
201 let z = (x.clone() + y.clone()).unwrap();
202 assert_eq!(z, Value::from(69i8));
203 }
204
205 #[test]
206 fn list() {
207 init_logger_debug();
208 let mut a = List::from(vec![
209 Value::from("42"),
210 Value::from(42),
211 Value::from(true),
212 ]);
213
214 a.push(Value::from(42));
215 a.push(4);
216
217 assert_eq!(a.len(), 5);
218
219 let b = List::from(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
220 assert_eq!(b.len(), 11);
221
222 let c = datex_list![1, "test", 3, true, false];
223 assert_eq!(c.len(), 5);
224 assert_eq!(c[0], 1.into());
225 assert_eq!(c[1], "test".into());
226 assert_eq!(c[2], 3.into());
227 }
228
229 #[test]
230 fn boolean() {
231 init_logger_debug();
232 let a = Value::from(true);
233 let b = Value::from(false);
234 let c = Value::from(false);
235 assert_ne!(a, b);
236 assert_eq!(b, c);
237
238 let d = (!b.clone()).unwrap();
239 assert_eq!(a, d);
240
241 let a_plus_b = a.clone() + b.clone();
243 assert!(a_plus_b.is_err());
244 }
245
246 #[test]
247 fn equality_same_type() {
248 init_logger_debug();
249 let a = Value::from(42i8);
250 let b = Value::from(42i8);
251 let c = Value::from(27i8);
252
253 assert_eq!(a, b);
254 assert_ne!(a, c);
255 assert_ne!(b, c);
256
257 info!("{} === {}", a.clone(), b.clone());
258 info!("{} !== {}", a.clone(), c.clone());
259 }
260
261 #[test]
262 fn decimal() {
263 init_logger_debug();
264 let a = Value::from(42.1f32);
265 let b = Value::from(27f32);
266
267 let a_plus_b = (a.clone() + b.clone()).unwrap();
268 assert_eq!(a_plus_b, Value::from(69.1f32));
269 info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
270 }
271
272 #[test]
273 fn null() {
274 init_logger_debug();
275
276 let null_value = Value::null();
277 assert_eq!(null_value.to_string(), "null");
278
279 let maybe_value: Option<i8> = None;
280 let null_value = Value::from(maybe_value);
281 assert_eq!(null_value.to_string(), "null");
282 assert!(null_value.is_null());
283 }
284
285 #[test]
286 fn addition() {
287 init_logger_debug();
288 let a = Value::from(42i8);
289 let b = Value::from(27i8);
290
291 let a_plus_b = (a.clone() + b.clone()).unwrap();
292 assert_eq!(a_plus_b, Value::from(69i8));
293 info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
294 }
295
296 #[test]
297 fn string_concatenation() {
298 init_logger_debug();
299 let a = Value::from("Hello ");
300 let b = Value::from(42i8);
301
302 assert!(a.is_text());
303 assert!(b.is_integer_i8());
304
305 let a_plus_b = (a.clone() + b.clone()).unwrap();
306 let b_plus_a = (b.clone() + a.clone()).unwrap();
307
308 assert!(a_plus_b.is_text());
309 assert!(b_plus_a.is_text());
310
311 assert_eq!(a_plus_b, Value::from("Hello 42"));
312 assert_eq!(b_plus_a, Value::from("42Hello "));
313
314 info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b);
315 info!("{} + {} = {}", b.clone(), a.clone(), b_plus_a);
316 }
317
318 #[test]
319 fn structural_equality() {
320 let a = Value::from(42_i8);
321 let b = Value::from(42_i32);
322 assert!(a.is_integer_i8());
323
324 assert_structural_eq!(a, b);
325
326 assert_structural_eq!(
327 Value::from(TypedInteger::I8(42)),
328 Value::from(TypedInteger::U32(42)),
329 );
330
331 assert_structural_eq!(
332 Value::from(42_i8),
333 Value::from(Integer::from(42_i8))
334 );
335 }
336}