datex_core/values/
core_value.rs

1use datex_macros::FromCoreValue;
2
3use crate::libs::core::{CoreLibPointerId, get_core_lib_type};
4use crate::traits::structural_eq::StructuralEq;
5use crate::traits::value_eq::ValueEq;
6use crate::types::type_container::TypeContainer;
7use crate::values::core_values::boolean::Boolean;
8use crate::values::core_values::decimal::Decimal;
9use crate::values::core_values::decimal::typed_decimal::{
10    DecimalTypeVariant, TypedDecimal,
11};
12use crate::values::core_values::endpoint::Endpoint;
13use crate::values::core_values::integer::Integer;
14use crate::values::core_values::integer::typed_integer::{
15    IntegerTypeVariant, TypedInteger,
16};
17use crate::values::core_values::list::List;
18use crate::values::core_values::map::Map;
19use crate::values::core_values::text::Text;
20use crate::values::core_values::r#type::Type;
21use crate::values::value_container::{ValueContainer, ValueError};
22use std::fmt::{Display, Formatter};
23use std::ops::{Add, AddAssign, Neg, Not, Sub};
24
25#[derive(Clone, Debug, PartialEq, Eq, Hash, FromCoreValue)]
26pub enum CoreValue {
27    Null,
28    Boolean(Boolean),
29    Integer(Integer),
30    TypedInteger(TypedInteger),
31    Decimal(Decimal),
32    TypedDecimal(TypedDecimal),
33    Text(Text),
34    Endpoint(Endpoint),
35    List(List),
36    Map(Map),
37    Type(Type),
38}
39impl StructuralEq for CoreValue {
40    fn structural_eq(&self, other: &Self) -> bool {
41        match (self, other) {
42            (CoreValue::Boolean(a), CoreValue::Boolean(b)) => {
43                a.structural_eq(b)
44            }
45
46            // Integers
47            (CoreValue::Integer(a), CoreValue::Integer(b)) => {
48                a.structural_eq(b)
49            }
50
51            // TypedIntegers
52            (CoreValue::TypedInteger(a), CoreValue::TypedInteger(b)) => {
53                a.structural_eq(b)
54            }
55
56            // Integers + TypedIntegers
57            (CoreValue::Integer(a), CoreValue::TypedInteger(b))
58            | (CoreValue::TypedInteger(b), CoreValue::Integer(a)) => {
59                TypedInteger::Big(a.clone()).structural_eq(b)
60            }
61
62            // Decimals
63            (CoreValue::Decimal(a), CoreValue::Decimal(b)) => {
64                a.structural_eq(b)
65            }
66
67            // TypedDecimals
68            (CoreValue::TypedDecimal(a), CoreValue::TypedDecimal(b)) => {
69                a.structural_eq(b)
70            }
71
72            // Decimal + TypedDecimal
73            (CoreValue::Decimal(a), CoreValue::TypedDecimal(b))
74            | (CoreValue::TypedDecimal(b), CoreValue::Decimal(a)) => {
75                TypedDecimal::Decimal(a.clone()).structural_eq(b)
76            }
77
78            (CoreValue::Text(a), CoreValue::Text(b)) => a.structural_eq(b),
79            (CoreValue::Null, CoreValue::Null) => true,
80            (CoreValue::Endpoint(a), CoreValue::Endpoint(b)) => {
81                a.structural_eq(b)
82            }
83            (CoreValue::List(a), CoreValue::List(b)) => a.structural_eq(b),
84            (CoreValue::Map(a), CoreValue::Map(b)) => a.structural_eq(b),
85            _ => false,
86        }
87    }
88}
89
90/// Value equality corresponds to partial equality for all values,
91/// except for decimals, where partial equality is also given for NaN values and +0.0 and -0.0.
92/// Therefore, we ValueEq is used instead for decimals
93impl ValueEq for CoreValue {
94    fn value_eq(&self, other: &Self) -> bool {
95        match (self, other) {
96            (CoreValue::Decimal(a), CoreValue::Decimal(b)) => a.value_eq(b),
97            (CoreValue::TypedDecimal(a), CoreValue::TypedDecimal(b)) => {
98                a.value_eq(b)
99            }
100            _ => self == other,
101        }
102    }
103}
104
105impl From<&str> for CoreValue {
106    fn from(value: &str) -> Self {
107        CoreValue::Text(value.into())
108    }
109}
110impl From<String> for CoreValue {
111    fn from(value: String) -> Self {
112        CoreValue::Text(Text(value))
113    }
114}
115
116impl<T> From<Vec<T>> for CoreValue
117where
118    T: Into<ValueContainer>,
119{
120    fn from(vec: Vec<T>) -> Self {
121        CoreValue::List(vec.into())
122    }
123}
124
125impl<T> FromIterator<T> for CoreValue
126where
127    T: Into<ValueContainer>,
128{
129    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
130        CoreValue::List(List::new(iter.into_iter().map(Into::into).collect()))
131    }
132}
133
134impl From<bool> for CoreValue {
135    fn from(value: bool) -> Self {
136        CoreValue::Boolean(value.into())
137    }
138}
139
140impl From<i8> for CoreValue {
141    fn from(value: i8) -> Self {
142        CoreValue::TypedInteger(value.into())
143    }
144}
145impl From<i16> for CoreValue {
146    fn from(value: i16) -> Self {
147        CoreValue::TypedInteger(value.into())
148    }
149}
150impl From<i32> for CoreValue {
151    fn from(value: i32) -> Self {
152        CoreValue::TypedInteger(value.into())
153    }
154}
155impl From<i64> for CoreValue {
156    fn from(value: i64) -> Self {
157        CoreValue::TypedInteger(value.into())
158    }
159}
160impl From<i128> for CoreValue {
161    fn from(value: i128) -> Self {
162        CoreValue::TypedInteger(value.into())
163    }
164}
165
166impl From<u8> for CoreValue {
167    fn from(value: u8) -> Self {
168        CoreValue::TypedInteger(value.into())
169    }
170}
171impl From<u16> for CoreValue {
172    fn from(value: u16) -> Self {
173        CoreValue::TypedInteger(value.into())
174    }
175}
176impl From<u32> for CoreValue {
177    fn from(value: u32) -> Self {
178        CoreValue::TypedInteger(value.into())
179    }
180}
181impl From<u64> for CoreValue {
182    fn from(value: u64) -> Self {
183        CoreValue::TypedInteger(value.into())
184    }
185}
186impl From<u128> for CoreValue {
187    fn from(value: u128) -> Self {
188        CoreValue::TypedInteger(value.into())
189    }
190}
191
192impl From<f32> for CoreValue {
193    fn from(value: f32) -> Self {
194        CoreValue::TypedDecimal(value.into())
195    }
196}
197impl From<f64> for CoreValue {
198    fn from(value: f64) -> Self {
199        CoreValue::TypedDecimal(value.into())
200    }
201}
202
203impl From<&CoreValue> for CoreLibPointerId {
204    fn from(value: &CoreValue) -> Self {
205        match value {
206            CoreValue::Map(_) => CoreLibPointerId::Map,
207            CoreValue::List(_) => CoreLibPointerId::List,
208            CoreValue::Text(_) => CoreLibPointerId::Text,
209            CoreValue::Boolean(_) => CoreLibPointerId::Boolean,
210            CoreValue::TypedInteger(i) => CoreLibPointerId::from(i),
211            CoreValue::TypedDecimal(d) => CoreLibPointerId::from(d),
212            CoreValue::Integer(_) => CoreLibPointerId::Integer(None),
213            CoreValue::Decimal(_) => CoreLibPointerId::Decimal(None),
214            CoreValue::Endpoint(_) => CoreLibPointerId::Endpoint,
215            CoreValue::Null => CoreLibPointerId::Null,
216            CoreValue::Type(_) => CoreLibPointerId::Type,
217        }
218    }
219}
220
221impl CoreValue {
222    pub fn new<T>(value: T) -> CoreValue
223    where
224        CoreValue: From<T>,
225    {
226        value.into()
227    }
228
229    /// Check if the CoreValue is a combined value type (List, Map)
230    /// that contains inner ValueContainers.
231    pub fn is_collection_value(&self) -> bool {
232        matches!(self, CoreValue::List(_) | CoreValue::Map(_))
233    }
234
235    /// Get the default type of the CoreValue as a TypeContainer.
236    /// This method uses the CoreLibPointerId to retrieve the corresponding
237    /// type reference from the core library.
238    /// For example, a CoreValue::TypedInteger(i32) will return the type ref integer/i32
239    pub fn default_type(&self) -> TypeContainer {
240        get_core_lib_type(CoreLibPointerId::from(self))
241    }
242
243    // TODO #313: allow cast of any CoreValue to Type, as structural type can always be constructed?
244    // This method may be not required, the cast should be performed on the ValueContainer level
245    pub fn cast_to_type(&self) -> Option<&Type> {
246        match self {
247            CoreValue::Type(ty) => Some(ty),
248            _ => None,
249        }
250    }
251
252    pub fn cast_to_text(&self) -> Text {
253        match self {
254            CoreValue::Text(text) => text.clone(),
255            _ => Text(self.to_string()),
256        }
257    }
258
259    pub fn cast_to_bool(&self) -> Option<Boolean> {
260        match self {
261            CoreValue::Text(text) => Some(Boolean(!text.0.is_empty())),
262            CoreValue::Boolean(bool) => Some(bool.clone()),
263            CoreValue::TypedInteger(int) => Some(Boolean(int.as_i128()? != 0)),
264            CoreValue::Null => Some(Boolean(false)),
265            _ => None,
266        }
267    }
268
269    pub fn cast_to_decimal(&self) -> Option<Decimal> {
270        match self {
271            CoreValue::Text(text) => {
272                text.to_string().parse::<f64>().ok().map(Decimal::from)
273            }
274            CoreValue::TypedInteger(int) => {
275                Some(Decimal::from(int.as_i128()? as f64))
276            }
277            CoreValue::TypedDecimal(decimal) => {
278                Some(Decimal::from(decimal.clone()))
279            }
280            CoreValue::Integer(int) => {
281                Some(Decimal::from(int.as_i128()? as f64))
282            }
283            CoreValue::Decimal(decimal) => Some(decimal.clone()),
284            _ => None,
285        }
286    }
287
288    pub fn cast_to_typed_decimal(
289        &self,
290        variant: DecimalTypeVariant,
291    ) -> Option<TypedDecimal> {
292        match self {
293            CoreValue::Text(text) => {
294                TypedDecimal::from_string_and_variant_in_range(
295                    text.as_str(),
296                    variant,
297                )
298                .ok()
299            }
300            CoreValue::TypedInteger(int) => Some(
301                TypedDecimal::from_string_and_variant_in_range(
302                    &int.to_string(),
303                    variant,
304                )
305                .ok()?,
306            ),
307            CoreValue::TypedDecimal(decimal) => Some(
308                TypedDecimal::from_string_and_variant_in_range(
309                    &decimal.to_string(),
310                    variant,
311                )
312                .ok()?,
313            ),
314            CoreValue::Integer(int) => Some(
315                TypedDecimal::from_string_and_variant_in_range(
316                    &int.to_string(),
317                    variant,
318                )
319                .ok()?,
320            ),
321            CoreValue::Decimal(decimal) => Some(
322                TypedDecimal::from_string_and_variant_in_range(
323                    &decimal.to_string(),
324                    variant,
325                )
326                .ok()?,
327            ),
328            _ => None,
329        }
330    }
331
332    // FIXME #314 discuss here - shall we fit the integer in the minimum viable type?
333    pub fn _cast_to_integer_internal(&self) -> Option<TypedInteger> {
334        match self {
335            CoreValue::Text(text) => Integer::from_string(&text.to_string())
336                .map(|x| Some(x.to_smallest_fitting()))
337                .unwrap_or(None),
338            CoreValue::TypedInteger(int) => {
339                Some(int.to_smallest_fitting().clone())
340            }
341            CoreValue::Integer(int) => {
342                Some(TypedInteger::Big(int.clone()).to_smallest_fitting())
343            }
344            CoreValue::Decimal(decimal) => Some(
345                TypedInteger::from(decimal.into_f64() as i128)
346                    .to_smallest_fitting(),
347            ),
348            CoreValue::TypedDecimal(decimal) => Some(
349                TypedInteger::from(decimal.as_f64() as i64)
350                    .to_smallest_fitting(),
351            ),
352            _ => None,
353        }
354    }
355
356    // TODO #315 improve conversion logic
357    pub fn cast_to_integer(&self) -> Option<Integer> {
358        match self {
359            CoreValue::Text(text) => {
360                Integer::from_string(&text.to_string()).ok()
361            }
362            CoreValue::TypedInteger(int) => Some(int.as_integer()),
363            CoreValue::Integer(int) => Some(int.clone()),
364            CoreValue::Decimal(decimal) => {
365                // FIXME #316 currently bad as f64 can be infinity or nan
366                // convert decimal directly to integer into_f64 is wrong here
367                Some(Integer::from(decimal.into_f64() as i128))
368            }
369            CoreValue::TypedDecimal(decimal) => {
370                decimal.as_integer().map(Integer::from)
371            }
372            _ => None,
373        }
374    }
375
376    pub fn cast_to_typed_integer(
377        &self,
378        variant: IntegerTypeVariant,
379    ) -> Option<TypedInteger> {
380        match self {
381            CoreValue::Text(text) => {
382                TypedInteger::from_string_with_variant(text.as_str(), variant)
383                    .ok()
384            }
385            CoreValue::TypedInteger(int) => {
386                TypedInteger::from_string_with_variant(
387                    &int.to_string(),
388                    variant,
389                )
390                .ok()
391            }
392            CoreValue::Integer(int) => TypedInteger::from_string_with_variant(
393                int.to_string().as_str(),
394                variant,
395            )
396            .ok(),
397            CoreValue::Decimal(decimal) => {
398                Some(TypedInteger::from(decimal.into_f64() as i128))
399            }
400            CoreValue::TypedDecimal(decimal) => {
401                decimal.as_integer().map(TypedInteger::from)
402            }
403            _ => None,
404        }
405    }
406
407    pub fn cast_to_endpoint(&self) -> Option<Endpoint> {
408        match self {
409            CoreValue::Text(text) => Endpoint::try_from(text.as_str()).ok(),
410            CoreValue::Endpoint(endpoint) => Some(endpoint.clone()),
411            _ => None,
412        }
413    }
414
415    pub fn cast_to_list(&self) -> Option<List> {
416        match self {
417            CoreValue::List(list) => Some(list.clone()),
418            _ => None,
419        }
420    }
421
422    pub fn cast_to_map(&self) -> Option<Map> {
423        match self {
424            CoreValue::Map(map) => Some(map.clone()),
425            _ => None,
426        }
427    }
428}
429
430impl Add for CoreValue {
431    type Output = Result<CoreValue, ValueError>;
432    fn add(self, rhs: CoreValue) -> Self::Output {
433        match (&self, &rhs) {
434            // x + text or text + x (order does not matter)
435            (CoreValue::Text(text), other) => {
436                let other = other.cast_to_text();
437                return Ok(CoreValue::Text(text + other));
438            }
439            (other, CoreValue::Text(text)) => {
440                let other = other.cast_to_text();
441                return Ok(CoreValue::Text(other + text));
442            }
443
444            // same type additions
445            (CoreValue::TypedInteger(lhs), CoreValue::TypedInteger(rhs)) => {
446                return Ok(CoreValue::TypedInteger(
447                    (lhs + rhs).ok_or(ValueError::IntegerOverflow)?,
448                ));
449            }
450            (CoreValue::Integer(lhs), CoreValue::Integer(rhs)) => {
451                return Ok(CoreValue::Integer(lhs + rhs));
452            }
453            (CoreValue::TypedDecimal(lhs), CoreValue::TypedDecimal(rhs)) => {
454                return Ok(CoreValue::TypedDecimal(lhs + rhs));
455            }
456            (CoreValue::Decimal(lhs), CoreValue::Decimal(rhs)) => {
457                return Ok(CoreValue::Decimal(lhs + rhs));
458            }
459
460            _ => {}
461        }
462
463        // other cases
464        match &self {
465            // integer
466            CoreValue::Integer(lhs) => match &rhs {
467                CoreValue::TypedInteger(rhs) => {
468                    Ok(CoreValue::Integer((lhs.clone() + rhs.as_integer())))
469                }
470                CoreValue::Decimal(_) => {
471                    let integer = rhs
472                        ._cast_to_integer_internal()
473                        .ok_or(ValueError::InvalidOperation)?;
474                    Ok(CoreValue::Integer((lhs.clone() + integer.as_integer())))
475                }
476                CoreValue::TypedDecimal(rhs) => {
477                    let decimal = rhs.as_f64();
478                    let integer = TypedInteger::from(decimal as i128);
479                    Ok(CoreValue::Integer((lhs.clone() + integer.as_integer())))
480                }
481                _ => Err(ValueError::InvalidOperation),
482            },
483
484            // typed integer
485            CoreValue::TypedInteger(lhs) => match &rhs {
486                CoreValue::Integer(rhs) => {
487                    todo!("#317 TypedInteger + Integer not implemented yet");
488                    //Ok(CoreValue::TypedInteger(lhs.as_integer() + rhs.clone()))
489                }
490                CoreValue::Decimal(_) => {
491                    let integer = rhs
492                        ._cast_to_integer_internal()
493                        .ok_or(ValueError::InvalidOperation)?;
494                    Ok(CoreValue::TypedInteger(
495                        (lhs + &integer).ok_or(ValueError::IntegerOverflow)?,
496                    ))
497                }
498                CoreValue::TypedDecimal(rhs) => {
499                    let decimal = rhs.as_f64();
500                    let integer = TypedInteger::from(decimal as i128);
501                    Ok(CoreValue::TypedInteger(
502                        (lhs + &integer).ok_or(ValueError::IntegerOverflow)?,
503                    ))
504                }
505                _ => Err(ValueError::InvalidOperation),
506            },
507
508            // decimal
509            CoreValue::Decimal(lhs) => match rhs {
510                CoreValue::TypedDecimal(rhs) => {
511                    Ok(CoreValue::Decimal(lhs + &Decimal::from(rhs)))
512                }
513                CoreValue::TypedInteger(rhs) => {
514                    let decimal = Decimal::from(
515                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
516                            as f64,
517                    );
518                    Ok(CoreValue::Decimal(lhs + &decimal))
519                }
520                CoreValue::Integer(rhs) => {
521                    let decimal = Decimal::from(
522                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
523                            as f64,
524                    );
525                    Ok(CoreValue::Decimal(lhs + &decimal))
526                }
527                _ => Err(ValueError::InvalidOperation),
528            },
529
530            // typed decimal
531            CoreValue::TypedDecimal(lhs) => match rhs {
532                CoreValue::Decimal(rhs) => Ok(CoreValue::TypedDecimal(
533                    lhs + &TypedDecimal::Decimal(rhs),
534                )),
535                CoreValue::TypedInteger(rhs) => {
536                    let decimal = TypedDecimal::from(
537                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
538                            as f64,
539                    );
540                    Ok(CoreValue::TypedDecimal(lhs + &decimal))
541                }
542                CoreValue::Integer(rhs) => {
543                    let decimal = TypedDecimal::from(
544                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
545                            as f64,
546                    );
547                    Ok(CoreValue::TypedDecimal(lhs + &decimal))
548                }
549                _ => Err(ValueError::InvalidOperation),
550            },
551
552            _ => Err(ValueError::InvalidOperation),
553        }
554    }
555}
556
557impl Add for &CoreValue {
558    type Output = Result<CoreValue, ValueError>;
559    fn add(self, rhs: &CoreValue) -> Self::Output {
560        CoreValue::add(self.clone(), rhs.clone())
561    }
562}
563
564impl Sub for CoreValue {
565    type Output = Result<CoreValue, ValueError>;
566    fn sub(self, rhs: CoreValue) -> Self::Output {
567        // same type subtractions
568        match (&self, &rhs) {
569            (CoreValue::TypedInteger(lhs), CoreValue::TypedInteger(rhs)) => {
570                return Ok(CoreValue::TypedInteger(
571                    (lhs - rhs).ok_or(ValueError::IntegerOverflow)?,
572                ));
573            }
574            (CoreValue::Integer(lhs), CoreValue::Integer(rhs)) => {
575                return Ok(CoreValue::Integer(lhs - rhs));
576            }
577            (CoreValue::TypedDecimal(lhs), CoreValue::TypedDecimal(rhs)) => {
578                return Ok(CoreValue::TypedDecimal(lhs - rhs));
579            }
580            (CoreValue::Decimal(lhs), CoreValue::Decimal(rhs)) => {
581                return Ok(CoreValue::Decimal(lhs - rhs));
582            }
583
584            _ => {}
585        }
586
587        // other cases
588        match &self {
589            // integer
590            CoreValue::Integer(lhs) => match &rhs {
591                CoreValue::TypedInteger(rhs) => {
592                    Ok(CoreValue::Integer((lhs - &rhs.as_integer())))
593                }
594                CoreValue::Decimal(_) => {
595                    let integer = rhs
596                        ._cast_to_integer_internal()
597                        .ok_or(ValueError::InvalidOperation)?;
598                    Ok(CoreValue::Integer((lhs - &integer.as_integer())))
599                }
600                CoreValue::TypedDecimal(rhs) => {
601                    let decimal = rhs.as_f64();
602                    let integer = TypedInteger::from(decimal as i128);
603                    Ok(CoreValue::Integer((lhs - &integer.as_integer())))
604                }
605                _ => Err(ValueError::InvalidOperation),
606            },
607
608            // typed integer
609            CoreValue::TypedInteger(lhs) => match &rhs {
610                CoreValue::Integer(rhs) => {
611                    todo!("#318 TypedInteger - Integer not implemented yet");
612                    //Ok(CoreValue::TypedInteger(lhs.as_integer() - rhs.clone()))
613                }
614                //     Ok(CoreValue::TypedInteger(
615                //     (lhs - &rhs.0).ok_or(ValueError::IntegerOverflow)?,
616                // ))
617                CoreValue::Decimal(_) => {
618                    let integer = rhs
619                        ._cast_to_integer_internal()
620                        .ok_or(ValueError::InvalidOperation)?;
621                    Ok(CoreValue::TypedInteger(
622                        (lhs - &integer).ok_or(ValueError::IntegerOverflow)?,
623                    ))
624                }
625                CoreValue::TypedDecimal(rhs) => {
626                    let decimal = rhs.as_f64();
627                    let integer = TypedInteger::from(decimal as i128);
628                    Ok(CoreValue::TypedInteger(
629                        (lhs - &integer).ok_or(ValueError::IntegerOverflow)?,
630                    ))
631                }
632                _ => Err(ValueError::InvalidOperation),
633            },
634
635            // decimal
636            CoreValue::Decimal(lhs) => match rhs {
637                CoreValue::TypedDecimal(rhs) => {
638                    Ok(CoreValue::Decimal(lhs - &Decimal::from(rhs)))
639                }
640                CoreValue::TypedInteger(rhs) => {
641                    let decimal = Decimal::from(
642                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
643                            as f64,
644                    );
645                    Ok(CoreValue::Decimal(lhs - &decimal))
646                }
647                CoreValue::Integer(rhs) => {
648                    let decimal = Decimal::from(
649                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
650                            as f64,
651                    );
652                    Ok(CoreValue::Decimal(lhs - &decimal))
653                }
654                _ => Err(ValueError::InvalidOperation),
655            },
656
657            // typed decimal
658            CoreValue::TypedDecimal(lhs) => match rhs {
659                CoreValue::Decimal(rhs) => Ok(CoreValue::TypedDecimal(
660                    lhs - &TypedDecimal::Decimal(rhs),
661                )),
662                CoreValue::TypedInteger(rhs) => {
663                    let decimal = TypedDecimal::from(
664                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
665                            as f64,
666                    );
667                    Ok(CoreValue::TypedDecimal(lhs - &decimal))
668                }
669                CoreValue::Integer(rhs) => {
670                    let decimal = TypedDecimal::from(
671                        rhs.as_i128().ok_or(ValueError::IntegerOverflow)?
672                            as f64,
673                    );
674                    Ok(CoreValue::TypedDecimal(lhs - &decimal))
675                }
676                _ => Err(ValueError::InvalidOperation),
677            },
678            _ => Err(ValueError::InvalidOperation),
679        }
680    }
681}
682
683impl Sub for &CoreValue {
684    type Output = Result<CoreValue, ValueError>;
685    fn sub(self, rhs: &CoreValue) -> Self::Output {
686        CoreValue::sub(self.clone(), rhs.clone())
687    }
688}
689
690impl AddAssign<CoreValue> for CoreValue {
691    fn add_assign(&mut self, rhs: CoreValue) {
692        let res = self.clone() + rhs;
693        if let Ok(value) = res {
694            *self = value;
695        } else {
696            panic!("Failed to add value: {res:?}");
697        }
698    }
699}
700
701impl Not for CoreValue {
702    type Output = Option<CoreValue>;
703
704    fn not(self) -> Self::Output {
705        match self {
706            CoreValue::Boolean(bool) => Some(CoreValue::Boolean(!bool)),
707            _ => None, // Not applicable for other types
708        }
709    }
710}
711
712impl Neg for CoreValue {
713    type Output = Result<CoreValue, ValueError>;
714
715    fn neg(self) -> Self::Output {
716        match self {
717            CoreValue::TypedInteger(int) => {
718                Ok(CoreValue::TypedInteger(int.neg()?))
719            }
720            CoreValue::Integer(int) => Ok(CoreValue::Integer(int.neg())),
721            CoreValue::TypedDecimal(decimal) => {
722                Ok(CoreValue::TypedDecimal(decimal.neg()))
723            }
724            CoreValue::Decimal(decimal) => {
725                Ok(CoreValue::Decimal(decimal.neg()))
726            }
727            _ => Err(ValueError::InvalidOperation), // Negation not applicable for other types
728        }
729    }
730}
731
732impl Display for CoreValue {
733    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
734        match self {
735            CoreValue::Type(ty) => write!(f, "{ty}"),
736            CoreValue::Boolean(bool) => write!(f, "{bool}"),
737            CoreValue::TypedInteger(int) => write!(f, "{int}"),
738            CoreValue::TypedDecimal(decimal) => write!(f, "{decimal}"),
739            CoreValue::Text(text) => write!(f, "{text}"),
740            CoreValue::Null => write!(f, "null"),
741            CoreValue::Endpoint(endpoint) => write!(f, "{endpoint}"),
742            CoreValue::Map(map) => write!(f, "{map}"),
743            CoreValue::Integer(integer) => write!(f, "{integer}"),
744            CoreValue::Decimal(decimal) => write!(f, "{decimal}"),
745            CoreValue::List(list) => write!(f, "{list}"),
746        }
747    }
748}
749
750#[cfg(test)]
751/// This module contains tests for the CoreValue struct.
752/// Each CoreValue is a representation of a underlying native value.
753/// The tests cover addition, casting, and type conversions.
754mod tests {
755    use log::{debug, info};
756
757    use crate::logger::init_logger_debug;
758
759    use super::*;
760
761    #[test]
762    fn type_construct() {
763        init_logger_debug();
764        let a = CoreValue::from(42i32);
765        assert_eq!(a.default_type().to_string(), "integer/i32");
766        assert_eq!(a.default_type().base_type().to_string(), "integer");
767    }
768
769    #[test]
770    fn addition() {
771        init_logger_debug();
772        let a = CoreValue::from(42i32);
773        let b = CoreValue::from(11i32);
774        let c = CoreValue::from("11");
775
776        let a_plus_b = (a.clone() + b.clone()).unwrap();
777        assert_eq!(a_plus_b.clone(), CoreValue::from(53));
778        info!("{} + {} = {}", a.clone(), b.clone(), a_plus_b.clone());
779    }
780
781    #[test]
782    fn endpoint() {
783        let endpoint: Endpoint = CoreValue::from("@test").try_into().unwrap();
784        debug!("Endpoint: {endpoint}");
785        assert_eq!(endpoint.to_string(), "@test");
786    }
787}