datex_core/values/
core_value.rs

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