Skip to main content

datex_core/values/
core_value.rs

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