Skip to main content

ranty/
value.rs

1use crate::gc::{Finalize, Trace};
2use crate::runtime::*;
3use crate::util::*;
4use crate::{
5    collections::*, gc, value_eq, FromRantyArgs, IntoRanty, RantySelectorHandle, TryFromRanty,
6};
7use crate::{lang::Slice, util, RantyFunction, RantyString};
8use cast::*;
9use std::cmp::Ordering;
10use std::error::Error;
11use std::ops::Deref;
12use std::{
13    fmt::{Debug, Display},
14    ops::{Add, Div, Mul, Neg, Not, Rem, Sub},
15};
16
17pub const TYPENAME_STRING: &str = "string";
18pub const TYPENAME_INT: &str = "int";
19pub const TYPENAME_FLOAT: &str = "float";
20pub const TYPENAME_BOOL: &str = "bool";
21pub const TYPENAME_TUPLE: &str = "tuple";
22pub const TYPENAME_LIST: &str = "list";
23pub const TYPENAME_MAP: &str = "map";
24pub const TYPENAME_FUNCTION: &str = "function";
25pub const TYPENAME_SELECTOR: &str = "selector";
26pub const TYPENAME_RANGE: &str = "range";
27pub const TYPENAME_NOTHING: &str = "nothing";
28
29const MAX_DISPLAY_STRING_DEPTH: usize = 4;
30
31/// Adds a barebones `Error` implementation to the specified type.
32macro_rules! impl_error_default {
33    ($t:ty) => {
34        impl Error for $t {
35            fn source(&self) -> Option<&(dyn Error + 'static)> {
36                None
37            }
38
39            fn cause(&self) -> Option<&dyn Error> {
40                self.source()
41            }
42        }
43    };
44}
45
46/// Implements `IntoRuntimeResult<T>` for a type.
47macro_rules! impl_into_runtime_result {
48    ($src_result_type:ty, $ok_type:ty, $err_type_variant:ident) => {
49        impl IntoRuntimeResult<$ok_type> for $src_result_type {
50            #[inline]
51            fn into_runtime_result(self) -> RuntimeResult<$ok_type> {
52                self.map_err(|err| RuntimeError {
53                    error_type: RuntimeErrorType::$err_type_variant(err),
54                    description: None,
55                    stack_trace: None,
56                })
57            }
58        }
59    };
60}
61
62/// The result type used by Ranty value operators and conversion.
63pub type ValueResult<T> = Result<T, ValueError>;
64/// The result type used by Ranty value index read operations.
65pub type ValueIndexResult = Result<RantyValue, IndexError>;
66/// The result type used by Ranty value key read operations.
67pub type ValueKeyResult = Result<RantyValue, KeyError>;
68/// The result type used by Ranty value index write operations.
69pub type ValueIndexSetResult = Result<(), IndexError>;
70/// The result type used by Ranty value key write operations.
71pub type ValueKeySetResult = Result<(), KeyError>;
72/// The result type used by Ranty value slice read operations.
73pub type ValueSliceResult = Result<RantyValue, SliceError>;
74/// The result type used by Ranty value slice write operations.
75pub type ValueSliceSetResult = Result<(), SliceError>;
76
77/// Type alias for the GC-managed function handle type.
78pub type RantyFunctionHandle = gc::Cc<RantyFunction>;
79
80/// Ranty's "nothing" value.
81pub struct RantyNothing;
82
83/// A lightweight representation of a Ranty value's type.
84#[derive(Copy, Clone, Debug, PartialEq)]
85#[repr(u8)]
86pub enum RantyValueType {
87    /// The `string` type.
88    String,
89    /// The `float` type.
90    Float,
91    /// The `int` type.
92    Int,
93    /// The `bool` type.
94    Boolean,
95    /// The `function` type.
96    Function,
97    /// The `list` type.
98    List,
99    /// The `tuple` type.
100    Tuple,
101    /// The `map` type.
102    Map,
103    /// The `selector` type.
104    Selector,
105    /// The `range` type.
106    Range,
107    /// The `nothing` type.
108    Nothing,
109}
110
111impl RantyValueType {
112    /// Gets a string slice representing the type.
113    pub fn name(&self) -> &'static str {
114        match self {
115            Self::String => TYPENAME_STRING,
116            Self::Float => TYPENAME_FLOAT,
117            Self::Int => TYPENAME_INT,
118            Self::Boolean => TYPENAME_BOOL,
119            Self::Function => TYPENAME_FUNCTION,
120            Self::List => TYPENAME_LIST,
121            Self::Tuple => TYPENAME_TUPLE,
122            Self::Map => TYPENAME_MAP,
123            Self::Selector => TYPENAME_SELECTOR,
124            Self::Range => TYPENAME_RANGE,
125            Self::Nothing => TYPENAME_NOTHING,
126        }
127    }
128}
129
130impl Display for RantyValueType {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        write!(f, "{}", self.name())
133    }
134}
135
136/// A dynamically-typed Ranty value.
137///
138/// ## Cloning
139///
140/// Calling `clone()` on a by-ref Ranty value type (such as `list`) will only clone its handle; both copies will point to the same contents.
141///
142/// If you want to shallow-copy a by-ref value, use the `shallow_copy` method instead.
143#[derive(Clone, Trace, Finalize)]
144#[rust_cc(unsafe_no_drop)]
145pub enum RantyValue {
146    /// A Ranty value of type `string`. Passed by-value.
147    String(RantyString),
148    /// A Ranty value of type `float`. Passed by-value.
149    Float(f64),
150    /// A Ranty value of type `int`. Passed by-value.
151    Int(i64),
152    /// A Ranty value of type `bool`. Passed by-value.
153    Boolean(bool),
154    /// A Ranty value of type `function`. Passed by-reference.
155    Function(RantyFunctionHandle),
156    /// A Ranty value of type `list`. Passed by-reference.
157    List(RantyListHandle),
158    /// A Ranty value of type `tuple`. Passed by-reference.
159    Tuple(RantyTupleHandle),
160    /// A Ranty value of type `map`. Passed by-reference.
161    Map(RantyMapHandle),
162    /// A Ranty value of type `range`. Passed by-value.
163    Range(RantyRange),
164    /// A Ranty value of type `selector`. Passed by-value.
165    Selector(RantySelectorHandle),
166    /// A Ranty unit value of type `nothing`. Passed by-value.
167    Nothing,
168}
169
170impl RantyValue {
171    /// Not a Number (NaN).
172    pub const NAN: Self = Self::Float(f64::NAN);
173    /// Positive infinity.
174    pub const INFINITY: Self = Self::Float(f64::INFINITY);
175    /// Negative infinity.
176    pub const NEG_INFINITY: Self = Self::Float(f64::NEG_INFINITY);
177    /// The lowest possible finite value for the `float` type.
178    pub const MIN_FLOAT: Self = Self::Float(f64::MIN);
179    /// The highest possible finite value for the `float` type.
180    pub const MAX_FLOAT: Self = Self::Float(f64::MAX);
181    /// The smallest possible `float` value greater than zero.
182    pub const EPSILON: Self = Self::Float(f64::EPSILON);
183    /// The lowest possible value for the `int` type.
184    pub const MIN_INT: Self = Self::Int(i64::MIN);
185    /// The highest possible value for the `int` type.
186    pub const MAX_INT: Self = Self::Int(i64::MAX);
187
188    /// Returns true if the value is of type `nothing`.
189    #[inline]
190    pub fn is_nothing(&self) -> bool {
191        matches!(self, RantyValue::Nothing)
192    }
193
194    /// Returns true if the value is NaN (Not a Number).
195    #[inline]
196    pub fn is_nan(&self) -> bool {
197        if let Self::Float(f) = self {
198            f64::is_nan(*f)
199        } else {
200            false
201        }
202    }
203
204    /// Returns true if the value is callable (e.g. a function).
205    #[inline]
206    pub fn is_callable(&self) -> bool {
207        matches!(self, Self::Function(..))
208    }
209}
210
211#[allow(clippy::len_without_is_empty)]
212impl RantyValue {
213    #[inline]
214    pub fn from_func<P: FromRantyArgs>(func: fn(&mut VM, P) -> Result<(), RuntimeError>) -> Self {
215        Self::Function(gc::alloc(RantyFunction::from_native(func)))
216    }
217
218    #[inline]
219    pub fn from_captured_func<P: FromRantyArgs>(
220        captures: Vec<RantyValue>,
221        func: fn(&mut VM, P, &[RantyValue]) -> Result<(), RuntimeError>,
222    ) -> Self {
223        Self::Function(gc::alloc(RantyFunction::from_captured_native(
224            captures, func,
225        )))
226    }
227
228    /// Interprets this value as a boolean value according to Ranty's truthiness rules.
229    ///
230    /// Types are converted as follows:
231    /// 1. `bool` returns itself.
232    /// 2. `int` returns `true` for any non-zero value; otherwise, `false`.
233    /// 3. `float` returns `true` for any nonzero, non-NaN value; otherwise, `false`.
234    /// 4. `empty` returns `false`.
235    /// 5. Collections that can be zero-length (`string`, `list`, `map`, `range`) return `true` if their length is nonzero; otherwise, `false`.
236    /// 6. All other types return `true`.
237    #[inline]
238    pub fn to_bool(&self) -> bool {
239        match self {
240            Self::Boolean(b) => *b,
241            Self::String(s) => !s.is_empty(),
242            Self::Float(n) => !n.is_nan() && *n != 0.0,
243            Self::Int(n) => *n != 0,
244            Self::Function(_) => true,
245            Self::List(l) => !l.borrow().is_empty(),
246            Self::Tuple(_) => true,
247            Self::Map(m) => !m.borrow().is_empty(),
248            Self::Range(r) => !r.is_empty(),
249            Self::Selector(_) => true,
250            Self::Nothing => false,
251        }
252    }
253
254    /// Converts to a Ranty `bool` value.
255    #[inline]
256    pub fn into_bool_value(self) -> Self {
257        Self::Boolean(self.to_bool())
258    }
259
260    /// Converts to a Ranty `int` value (or `empty` if the conversion fails).
261    #[inline]
262    pub fn into_int_value(self) -> Self {
263        match self {
264            Self::Int(_) => self,
265            Self::Float(n) => Self::Int(n as i64),
266            Self::String(s) => match s.as_str().parse() {
267                Ok(n) => Self::Int(n),
268                Err(_) => Self::Nothing,
269            },
270            Self::Boolean(b) => Self::Int(bi64(b)),
271            _ => Self::Nothing,
272        }
273    }
274
275    /// Converts to a Ranty `float` value (or `empty` if the conversion fails).
276    #[inline]
277    pub fn into_float_value(self) -> Self {
278        match self {
279            Self::Float(_) => self,
280            Self::Int(n) => Self::Float(n as f64),
281            Self::String(s) => match s.as_str().parse() {
282                Ok(n) => Self::Float(n),
283                Err(_) => Self::Nothing,
284            },
285            Self::Boolean(b) => Self::Float(bf64(b)),
286            _ => Self::Nothing,
287        }
288    }
289
290    /// Converts to a Ranty `string` value.
291    #[inline]
292    pub fn into_string_value(self) -> Self {
293        match self {
294            Self::String(_) => self,
295            _ => Self::String(self.to_string().into()),
296        }
297    }
298
299    /// Converts to a Ranty `list` value.
300    #[inline]
301    pub fn into_list_value(self) -> Self {
302        Self::List(
303            match self {
304                Self::Tuple(tuple) => tuple.to_ranty_list(),
305                Self::String(s) => s.to_ranty_list(),
306                Self::Range(range) => range.to_ranty_list(),
307                list @ Self::List(_) => return list,
308                _ => return RantyValue::Nothing,
309            }
310            .into_handle(),
311        )
312    }
313
314    /// Converts to a Ranty `tuple` value.
315    #[inline]
316    pub fn into_tuple_value(self) -> Self {
317        Self::Tuple(
318            match self {
319                Self::String(s) => s.to_ranty_tuple(),
320                Self::List(list) => list.borrow().to_ranty_tuple(),
321                Self::Range(range) => range.to_ranty_tuple(),
322                tuple @ RantyValue::Tuple(_) => return tuple,
323                _ => return RantyValue::Nothing,
324            }
325            .into_handle(),
326        )
327    }
328
329    /// Gets the length of the value.
330    #[inline]
331    pub fn len(&self) -> usize {
332        match self {
333            // Length of string is character count
334            Self::String(s) => s.len(),
335            // Length of list is element count
336            Self::List(lst) => lst.borrow().len(),
337            // Length of range is element count
338            Self::Range(range) => range.len(),
339            // Length of map is element count
340            Self::Map(map) => map.borrow().raw_len(),
341            // Length of tuple is element count
342            Self::Tuple(tuple) => tuple.len(),
343            // Treat everything else as length 1, since all other value types are primitives
344            _ => 1,
345        }
346    }
347
348    /// Returns true if the length of the value is 0.
349    #[inline]
350    pub fn is_empty(&self) -> bool {
351        self.len() == 0
352    }
353
354    #[inline]
355    pub fn reversed(&self) -> Self {
356        match self {
357            Self::String(s) => RantyValue::String(s.reversed()),
358            Self::Tuple(tuple) => {
359                RantyValue::Tuple(tuple.iter().rev().collect::<RantyTuple>().into_handle())
360            }
361            Self::List(list) => RantyValue::List(
362                list.borrow()
363                    .iter()
364                    .rev()
365                    .cloned()
366                    .collect::<RantyList>()
367                    .into_handle(),
368            ),
369            Self::Range(range) => RantyValue::Range(range.reversed()),
370            _ => self.clone(),
371        }
372    }
373
374    /// Returns a shallow copy of the value.
375    #[inline]
376    pub fn shallow_copy(&self) -> Self {
377        match self {
378            Self::List(list) => RantyValue::List(list.cloned()),
379            Self::Map(map) => RantyValue::Map(map.cloned()),
380            Self::Tuple(tuple) => RantyValue::Tuple(tuple.cloned()),
381            Self::Selector(special) => RantyValue::Selector(special.clone()),
382            _ => self.clone(),
383        }
384    }
385
386    /// Gets the Ranty type associated with the value.
387    #[inline]
388    pub fn get_type(&self) -> RantyValueType {
389        match self {
390            Self::String(_) => RantyValueType::String,
391            Self::Float(_) => RantyValueType::Float,
392            Self::Int(_) => RantyValueType::Int,
393            Self::Boolean(_) => RantyValueType::Boolean,
394            Self::Function(_) => RantyValueType::Function,
395            Self::List(_) => RantyValueType::List,
396            Self::Tuple(_) => RantyValueType::Tuple,
397            Self::Map(_) => RantyValueType::Map,
398            Self::Range(_) => RantyValueType::Range,
399            Self::Selector(_) => RantyValueType::Selector,
400            Self::Nothing => RantyValueType::Nothing,
401        }
402    }
403
404    /// Gets the type name of the value.
405    #[inline]
406    pub fn type_name(&self) -> &'static str {
407        self.get_type().name()
408    }
409
410    #[inline]
411    fn get_uindex(&self, index: i64) -> Option<usize> {
412        let uindex = if index < 0 {
413            self.len() as i64 + index
414        } else {
415            index
416        };
417
418        if uindex < 0 || uindex >= self.len() as i64 {
419            None
420        } else {
421            Some(uindex as usize)
422        }
423    }
424
425    #[inline]
426    fn get_ubound(&self, index: i64) -> Option<usize> {
427        let uindex = if index < 0 {
428            self.len() as i64 + index
429        } else {
430            index
431        };
432
433        if uindex < 0 || uindex > self.len() as i64 {
434            None
435        } else {
436            Some(uindex as usize)
437        }
438    }
439
440    #[inline]
441    fn get_uslice(&self, slice: &Slice) -> Option<(Option<usize>, Option<usize>)> {
442        match slice {
443            Slice::Full => Some((None, None)),
444            Slice::From(i) => Some((Some(self.get_ubound(*i)?), None)),
445            Slice::To(i) => Some((None, Some(self.get_ubound(*i)?))),
446            Slice::Between(l, r) => Some((Some(self.get_ubound(*l)?), Some(self.get_ubound(*r)?))),
447        }
448    }
449
450    pub fn slice_get(&self, slice: &Slice) -> ValueSliceResult {
451        let (slice_from, slice_to) = self.get_uslice(slice).ok_or(SliceError::OutOfRange)?;
452
453        match self {
454            Self::String(s) => Ok(Self::String(
455                s.to_slice(slice_from, slice_to)
456                    .ok_or(SliceError::OutOfRange)?,
457            )),
458            Self::Range(range) => Ok(Self::Range(range.sliced(slice_from, slice_to).unwrap())),
459            Self::List(list) => {
460                let list = list.borrow();
461                match (slice_from, slice_to) {
462                    (None, None) => Ok(self.shallow_copy()),
463                    (None, Some(to)) => Ok(Self::List(
464                        (&list[..to])
465                            .iter()
466                            .cloned()
467                            .collect::<RantyList>()
468                            .into_handle(),
469                    )),
470                    (Some(from), None) => Ok(Self::List(
471                        (&list[from..])
472                            .iter()
473                            .cloned()
474                            .collect::<RantyList>()
475                            .into_handle(),
476                    )),
477                    (Some(from), Some(to)) => {
478                        let (from, to) = util::minmax(from, to);
479                        Ok(Self::List(
480                            (&list[from..to])
481                                .iter()
482                                .cloned()
483                                .collect::<RantyList>()
484                                .into_handle(),
485                        ))
486                    }
487                }
488            }
489            Self::Tuple(tuple) => match (slice_from, slice_to) {
490                (None, None) => Ok(self.shallow_copy()),
491                (None, Some(to)) => Ok(Self::Tuple(
492                    (&tuple[..to])
493                        .iter()
494                        .cloned()
495                        .collect::<RantyTuple>()
496                        .into_handle(),
497                )),
498                (Some(from), None) => Ok(Self::Tuple(
499                    (&tuple[from..])
500                        .iter()
501                        .cloned()
502                        .collect::<RantyTuple>()
503                        .into_handle(),
504                )),
505                (Some(from), Some(to)) => {
506                    let (from, to) = util::minmax(from, to);
507                    Ok(Self::Tuple(
508                        (&tuple[from..to])
509                            .iter()
510                            .cloned()
511                            .collect::<RantyTuple>()
512                            .into_handle(),
513                    ))
514                }
515            },
516            other => Err(SliceError::CannotSliceType(other.get_type())),
517        }
518    }
519
520    pub fn slice_set(&mut self, slice: &Slice, val: RantyValue) -> ValueSliceSetResult {
521        let (slice_from, slice_to) = self.get_uslice(slice).ok_or(SliceError::OutOfRange)?;
522
523        match (self, &val) {
524            (Self::List(dst_list), Self::List(src_list)) => {
525                let src_list = src_list.borrow();
526                let mut dst_list = dst_list.borrow_mut();
527                let src = src_list.iter().cloned();
528                match (slice_from, slice_to) {
529                    (None, None) => {
530                        dst_list.splice(.., src);
531                    }
532                    (None, Some(to)) => {
533                        dst_list.splice(..to, src);
534                    }
535                    (Some(from), None) => {
536                        dst_list.splice(from.., src);
537                    }
538                    (Some(from), Some(to)) => {
539                        let (from, to) = util::minmax(from, to);
540                        dst_list.splice(from..to, src);
541                    }
542                }
543                Ok(())
544            }
545            (Self::List(dst_list), Self::Tuple(src_tuple)) => {
546                let mut dst_list = dst_list.borrow_mut();
547                let src = src_tuple.iter().cloned();
548                match (slice_from, slice_to) {
549                    (None, None) => {
550                        dst_list.splice(.., src);
551                    }
552                    (None, Some(to)) => {
553                        dst_list.splice(..to, src);
554                    }
555                    (Some(from), None) => {
556                        dst_list.splice(from.., src);
557                    }
558                    (Some(from), Some(to)) => {
559                        let (from, to) = util::minmax(from, to);
560                        dst_list.splice(from..to, src);
561                    }
562                }
563                Ok(())
564            }
565            (Self::List(_), other) => Err(SliceError::UnsupportedSpliceSource {
566                src: RantyValueType::List,
567                dst: other.get_type(),
568            }),
569            (dst, _src) => Err(SliceError::CannotSetSliceOnType(dst.get_type())),
570        }
571    }
572
573    /// Indicates whether the value can be indexed into.
574    #[inline]
575    pub fn is_indexable(&self) -> bool {
576        matches!(
577            self,
578            Self::String(_) | Self::List(_) | Self::Range(_) | Self::Tuple(_)
579        )
580    }
581
582    /// Attempts to get a value by index.
583    pub fn index_get(&self, index: i64) -> ValueIndexResult {
584        let uindex = self.get_uindex(index).ok_or(IndexError::OutOfRange)?;
585
586        match self {
587            Self::String(s) => {
588                if let Some(s) = s.grapheme_at(uindex) {
589                    Ok(Self::String(s))
590                } else {
591                    Err(IndexError::OutOfRange)
592                }
593            }
594            Self::List(list) => {
595                let list = list.borrow();
596                if uindex < list.len() {
597                    Ok(list[uindex].clone())
598                } else {
599                    Err(IndexError::OutOfRange)
600                }
601            }
602            Self::Range(range) => {
603                if let Some(item) = range.get(uindex) {
604                    Ok(Self::Int(item))
605                } else {
606                    Err(IndexError::OutOfRange)
607                }
608            }
609            Self::Tuple(tuple) => {
610                if uindex < tuple.len() {
611                    Ok(tuple[uindex].clone())
612                } else {
613                    Err(IndexError::OutOfRange)
614                }
615            }
616            _ => Err(IndexError::CannotIndexType(self.get_type())),
617        }
618    }
619
620    /// Attempts to set a value by index.
621    pub fn index_set(&mut self, index: i64, val: RantyValue) -> ValueIndexSetResult {
622        let uindex = self.get_uindex(index).ok_or(IndexError::OutOfRange)?;
623
624        match self {
625            Self::List(list) => {
626                let mut list = list.borrow_mut();
627
628                if uindex < list.len() {
629                    list[uindex] = val;
630                    Ok(())
631                } else {
632                    Err(IndexError::OutOfRange)
633                }
634            }
635            Self::Map(map) => {
636                let mut map = map.borrow_mut();
637                map.raw_set(uindex.to_string().as_str(), val);
638                Ok(())
639            }
640            _ => Err(IndexError::CannotSetIndexOnType(self.get_type())),
641        }
642    }
643
644    /// Attempts to get a value by key.
645    pub fn key_get(&self, key: &str) -> ValueKeyResult {
646        match self {
647            Self::Map(map) => {
648                let map = map.borrow();
649                if let Some(val) = map.get(key) {
650                    Ok(val.into_owned())
651                } else {
652                    Err(KeyError::KeyNotFound(key.to_owned()))
653                }
654            }
655            _ => Err(KeyError::CannotKeyType(self.get_type())),
656        }
657    }
658
659    /// Attempts to set a value by key.
660    pub fn key_set(&mut self, key: &str, val: RantyValue) -> ValueKeySetResult {
661        match self {
662            Self::Map(map) => {
663                let mut map = map.borrow_mut();
664                map.raw_set(key, val);
665                Ok(())
666            }
667            _ => Err(KeyError::CannotKeyType(self.get_type())),
668        }
669    }
670}
671
672impl Default for RantyValue {
673    /// Gets the default RantyValue (`empty`).
674    fn default() -> Self {
675        Self::Nothing
676    }
677}
678
679/// Error produced by a RantyValue operator or conversion.
680#[derive(Debug)]
681pub enum ValueError {
682    /// The requested conversion was not valid.
683    InvalidConversion {
684        from: &'static str,
685        to: &'static str,
686        message: Option<String>,
687    },
688    /// Attempted to divide by zero.
689    DivideByZero,
690    /// An arithmetic operation overflowed.
691    Overflow,
692}
693
694impl_error_default!(ValueError);
695
696impl Display for ValueError {
697    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
698        match self {
699            ValueError::InvalidConversion { from, to, message } => {
700                if let Some(message) = message {
701                    write!(f, "unable to convert from {} to {}: {}", from, to, message)
702                } else {
703                    write!(f, "unable to convert from {} to {}", from, to)
704                }
705            }
706            ValueError::DivideByZero => write!(f, "attempted to divide by zero"),
707            ValueError::Overflow => write!(f, "arithmetic overflow"),
708        }
709    }
710}
711
712impl<T> IntoRuntimeResult<T> for Result<T, ValueError> {
713    #[inline]
714    fn into_runtime_result(self) -> RuntimeResult<T> {
715        self.map_err(|err| RuntimeError {
716            error_type: RuntimeErrorType::ValueError(err),
717            description: None,
718            stack_trace: None,
719        })
720    }
721}
722
723/// Error produced by indexing a RantyValue.
724#[derive(Debug)]
725pub enum IndexError {
726    /// Index was out of range.
727    OutOfRange,
728    /// Values of this type cannot be indexed.
729    CannotIndexType(RantyValueType),
730    /// Values of this type cannot have indices written to.
731    CannotSetIndexOnType(RantyValueType),
732}
733
734impl_error_default!(IndexError);
735impl_into_runtime_result!(ValueIndexResult, RantyValue, IndexError);
736impl_into_runtime_result!(ValueIndexSetResult, (), IndexError);
737
738impl Display for IndexError {
739    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
740        match self {
741            IndexError::OutOfRange => write!(f, "value index is out of range"),
742            IndexError::CannotIndexType(t) => {
743                write!(f, "cannot read index on value of type '{}'", t)
744            }
745            IndexError::CannotSetIndexOnType(t) => {
746                write!(f, "cannot write index on value of type '{}'", t)
747            }
748        }
749    }
750}
751
752/// Error produced by keying a RantyValue.
753#[derive(Debug)]
754pub enum KeyError {
755    /// The specified key could not be found.
756    KeyNotFound(String),
757    /// Values of this type cannot be keyed.
758    CannotKeyType(RantyValueType),
759}
760
761impl_error_default!(KeyError);
762impl_into_runtime_result!(ValueKeyResult, RantyValue, KeyError);
763impl_into_runtime_result!(ValueKeySetResult, (), KeyError);
764
765impl Display for KeyError {
766    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
767        match self {
768            KeyError::KeyNotFound(k) => write!(f, "key not found: '{}'", k),
769            KeyError::CannotKeyType(t) => write!(f, "cannot key value of type '{}'", t),
770        }
771    }
772}
773
774/// Error produced by slicing a RantyValue.
775#[derive(Debug)]
776pub enum SliceError {
777    /// Slice is out of range.
778    OutOfRange,
779    /// Tried to slice with an unsupported bound type.
780    UnsupportedSliceBoundType(RantyValueType),
781    /// Type cannot be sliced.
782    CannotSliceType(RantyValueType),
783    /// Type cannot be spliced.
784    CannotSetSliceOnType(RantyValueType),
785    /// Type cannot be spliced with the specified source type.
786    UnsupportedSpliceSource {
787        src: RantyValueType,
788        dst: RantyValueType,
789    },
790}
791
792impl_error_default!(SliceError);
793impl_into_runtime_result!(ValueSliceResult, RantyValue, SliceError);
794impl_into_runtime_result!(ValueSliceSetResult, (), SliceError);
795
796impl Display for SliceError {
797    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
798        match self {
799            SliceError::OutOfRange => write!(f, "slice is out of range"),
800            SliceError::UnsupportedSliceBoundType(t) => {
801                write!(f, "cannot use '{}' value as slice bound", t)
802            }
803            SliceError::CannotSliceType(t) => write!(f, "cannot slice '{}' value", t),
804            SliceError::CannotSetSliceOnType(t) => write!(f, "cannot set slice on '{}' value", t),
805            SliceError::UnsupportedSpliceSource { src, dst } => {
806                write!(f, "cannot splice {} into {}", dst, src)
807            }
808        }
809    }
810}
811
812/// Represents a dynamically-typed Ranty number.
813///
814/// Implements `TryFromRanty` and can therefore be used on native functions to accept any number type (`int` or `float`),
815/// while preserving the original type.
816#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
817pub enum RantyNumber {
818    /// Ranty `int` value.
819    Int(i64),
820    /// Ranty `float` value.
821    Float(f64),
822}
823
824impl TryFromRanty for RantyNumber {
825    fn try_from_ranty(val: RantyValue) -> Result<Self, ValueError> {
826        match val {
827            RantyValue::Int(i) => Ok(RantyNumber::Int(i)),
828            RantyValue::Float(f) => Ok(RantyNumber::Float(f)),
829            other => Err(ValueError::InvalidConversion {
830                from: other.type_name(),
831                to: "[number]",
832                message: None,
833            }),
834        }
835    }
836
837    fn is_optional_param_type() -> bool {
838        false
839    }
840}
841
842/// Filter type that represents any indexable (ordered) Ranty collection type.
843///
844/// Use on native functions to accept any ordered collection type. Derefs to `RantyValue`.
845#[derive(Debug, Clone, PartialEq, PartialOrd)]
846pub struct RantyOrderedCollection(RantyValue);
847
848impl Deref for RantyOrderedCollection {
849    type Target = RantyValue;
850
851    fn deref(&self) -> &Self::Target {
852        &self.0
853    }
854}
855
856impl TryFromRanty for RantyOrderedCollection {
857    fn try_from_ranty(val: RantyValue) -> Result<Self, ValueError> {
858        if val.is_indexable() {
859            Ok(Self(val))
860        } else {
861            Err(ValueError::InvalidConversion {
862                from: val.type_name(),
863                to: "[ordered collection]",
864                message: Some(format!(
865                    "type '{}' is not an ordered collection type",
866                    val.type_name()
867                )),
868            })
869        }
870    }
871}
872
873impl Debug for RantyValue {
874    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
875        match self {
876            Self::String(s) => write!(f, "{}", s),
877            Self::Float(n) => write!(f, "{}", n),
878            Self::Int(n) => write!(f, "{}", n),
879            Self::Boolean(b) => write!(f, "{}", if *b { "@true" } else { "@false" }),
880            Self::Function(func) => write!(f, "[function({:?})]", func.body),
881            Self::List(l) => write!(f, "[list({})]", l.borrow().len()),
882            Self::Tuple(t) => write!(f, "[tuple({})]", t.len()),
883            Self::Map(m) => write!(f, "[map({})]", m.borrow().raw_len()),
884            Self::Range(range) => write!(f, "{}", range),
885            Self::Selector(special) => write!(f, "[special({:?})]", special),
886            Self::Nothing => write!(f, "[empty]"),
887        }
888    }
889}
890
891fn get_display_string(value: &RantyValue, max_depth: usize) -> String {
892    match value {
893        RantyValue::String(s) => s.to_string(),
894        RantyValue::Float(f) => format!("{}", f),
895        RantyValue::Int(i) => format!("{}", i),
896        RantyValue::Boolean(b) => (if *b { "@true" } else { "@false" }).to_string(),
897        RantyValue::Function(f) => format!("[function({:?})]", f.body),
898        RantyValue::List(list) => {
899            let mut buf = String::new();
900            let mut is_first = true;
901            buf.push_str("(:");
902            if !list.borrow().is_empty() {
903                buf.push(' ');
904            }
905            if max_depth > 0 {
906                for val in list.borrow().iter() {
907                    if is_first {
908                        is_first = false;
909                    } else {
910                        buf.push_str("; ");
911                    }
912                    buf.push_str(&get_display_string(val, max_depth - 1));
913                }
914            } else {
915                buf.push_str("...");
916            }
917            buf.push(')');
918            buf
919        }
920        RantyValue::Tuple(tuple) => {
921            let mut buf = String::new();
922            let mut is_first = true;
923            buf.push('(');
924            if max_depth > 0 {
925                for val in tuple.iter() {
926                    if is_first {
927                        is_first = false;
928                    } else {
929                        buf.push_str("; ");
930                    }
931                    buf.push_str(&get_display_string(val, max_depth - 1));
932                }
933            } else {
934                buf.push_str("...");
935            }
936            if tuple.len() == 1 {
937                buf.push(';');
938            }
939            buf.push(')');
940            buf
941        }
942        RantyValue::Map(map) => {
943            let mut buf = String::new();
944            let mut is_first = true;
945            buf.push_str("(::");
946            if !map.borrow().is_empty() {
947                buf.push(' ');
948            }
949            if max_depth > 0 {
950                let map = map.borrow();
951                for key in map.raw_keys() {
952                    let key_string = key.to_string();
953                    if let Some(val) = map.raw_get(&key_string) {
954                        if is_first {
955                            is_first = false;
956                        } else {
957                            buf.push_str("; ");
958                        }
959                        buf.push_str(&format!(
960                            "{} = {}",
961                            key_string,
962                            get_display_string(val, max_depth - 1)
963                        ));
964                    }
965                }
966            } else {
967                buf.push_str("...");
968            }
969            buf.push(')');
970            buf
971        }
972        RantyValue::Selector(_) => "[special]".to_owned(),
973        RantyValue::Range(range) => range.to_string(),
974        RantyValue::Nothing => (if max_depth < MAX_DISPLAY_STRING_DEPTH {
975            "<>"
976        } else {
977            ""
978        })
979        .to_owned(),
980    }
981}
982
983impl Display for RantyValue {
984    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
985        write!(f, "{}", get_display_string(self, MAX_DISPLAY_STRING_DEPTH))
986    }
987}
988
989impl PartialEq for RantyValue {
990    fn eq(&self, other: &Self) -> bool {
991        value_eq::values_equal(self, other)
992    }
993}
994
995impl Eq for RantyValue {}
996
997impl PartialOrd for RantyValue {
998    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
999        match (self, other) {
1000            (Self::Nothing, _) | (_, Self::Nothing) => None,
1001            (Self::Int(a), Self::Int(b)) => a.partial_cmp(b),
1002            (Self::Float(a), Self::Float(b)) => a.partial_cmp(b),
1003            (Self::Float(a), Self::Int(b)) => a.partial_cmp(&(*b as f64)),
1004            (Self::Int(a), Self::Float(b)) => (&(*a as f64)).partial_cmp(b),
1005            (Self::String(a), Self::String(b)) => a.partial_cmp(b),
1006            (a, b) => {
1007                if a == b {
1008                    Some(Ordering::Equal)
1009                } else {
1010                    None
1011                }
1012            }
1013        }
1014    }
1015}
1016
1017impl Not for RantyValue {
1018    type Output = Self;
1019    fn not(self) -> Self::Output {
1020        RantyValue::Boolean(!self.to_bool())
1021    }
1022}
1023
1024impl Neg for RantyValue {
1025    type Output = Self;
1026    fn neg(self) -> Self::Output {
1027        match self {
1028            Self::Int(a) => Self::Int(a.saturating_neg()),
1029            Self::Float(a) => Self::Float(-a),
1030            Self::Boolean(a) => Self::Int(-bi64(a)),
1031            _ => self,
1032        }
1033    }
1034}
1035
1036impl Add for RantyValue {
1037    type Output = Self;
1038    fn add(self, rhs: Self) -> Self::Output {
1039        match (self, rhs) {
1040            (Self::Nothing, Self::Nothing) => Self::Nothing,
1041            (lhs, Self::Nothing) => lhs,
1042            (Self::Nothing, rhs) => rhs,
1043            (Self::Int(a), Self::Int(b)) => Self::Int(a.saturating_add(b)),
1044            (Self::Int(a), Self::Float(b)) => Self::Float(f64(a) + b),
1045            (Self::Int(a), Self::Boolean(b)) => Self::Int(a.saturating_add(bi64(b))),
1046            (Self::Float(a), Self::Float(b)) => Self::Float(a + b),
1047            (Self::Float(a), Self::Int(b)) => Self::Float(a + f64(b)),
1048            (Self::Float(a), Self::Boolean(b)) => Self::Float(a + bf64(b)),
1049            (Self::String(a), Self::String(b)) => Self::String(a + b),
1050            (Self::String(a), rhs) => Self::String(a + rhs.to_string().into()),
1051            (Self::Boolean(a), Self::Boolean(b)) => Self::Int(bi64(a) + bi64(b)),
1052            (Self::Boolean(a), Self::Int(b)) => Self::Int(bi64(a).saturating_add(b)),
1053            (Self::Boolean(a), Self::Float(b)) => Self::Float(bf64(a) + b),
1054            (Self::Tuple(a), Self::Tuple(b)) => (a + b).into_ranty(),
1055            (Self::Tuple(a), Self::List(b)) => (a + b).into_ranty(),
1056            (Self::List(a), Self::List(b)) => (a + b).into_ranty(),
1057            (Self::List(a), Self::Tuple(b)) => (a + b).into_ranty(),
1058            (Self::Map(a), Self::Map(b)) => {
1059                let mut map = RantyMap::new();
1060                for (k, v) in a.borrow().raw_pairs_internal() {
1061                    map.raw_set(k, v.clone());
1062                }
1063                for (k, v) in b.borrow().raw_pairs_internal() {
1064                    map.raw_set(k, v.clone());
1065                }
1066                map.into_ranty()
1067            }
1068            (lhs, rhs) => Self::String(RantyString::from(format!("{}{}", lhs, rhs))),
1069        }
1070    }
1071}
1072
1073impl Sub for RantyValue {
1074    type Output = Self;
1075    fn sub(self, rhs: Self) -> Self::Output {
1076        match (self, rhs) {
1077            (Self::Nothing, Self::Nothing) => Self::Nothing,
1078            (lhs, Self::Nothing) => lhs,
1079            (Self::Nothing, rhs) => -rhs,
1080            (Self::Int(a), Self::Int(b)) => Self::Int(a.saturating_sub(b)),
1081            (Self::Int(a), Self::Float(b)) => Self::Float((a as f64) - b),
1082            (Self::Int(a), Self::Boolean(b)) => Self::Int(a - bi64(b)),
1083            (Self::Float(a), Self::Float(b)) => Self::Float(a - b),
1084            (Self::Float(a), Self::Int(b)) => Self::Float(a - (b as f64)),
1085            (Self::Float(a), Self::Boolean(b)) => Self::Float(a - bf64(b)),
1086            (Self::Boolean(a), Self::Boolean(b)) => Self::Int(bi64(a) - bi64(b)),
1087            (Self::Boolean(a), Self::Int(b)) => Self::Int(bi64(a).saturating_sub(b)),
1088            (Self::Boolean(a), Self::Float(b)) => Self::Float(bf64(a) - b),
1089            _ => Self::NAN,
1090        }
1091    }
1092}
1093
1094impl Mul for RantyValue {
1095    type Output = Self;
1096    fn mul(self, rhs: Self) -> Self::Output {
1097        match (self, rhs) {
1098            (Self::Nothing, _) | (_, Self::Nothing) => Self::Nothing,
1099            (Self::Int(a), Self::Int(b)) => Self::Int(a.saturating_mul(b)),
1100            (Self::Int(a), Self::Float(b)) => Self::Float((a as f64) * b),
1101            (Self::Int(a), Self::Boolean(b)) => Self::Int(a * bi64(b)),
1102            (Self::Float(a), Self::Float(b)) => Self::Float(a * b),
1103            (Self::Float(a), Self::Int(b)) => Self::Float(a * (b as f64)),
1104            (Self::Float(a), Self::Boolean(b)) => Self::Float(a * bf64(b)),
1105            (Self::Boolean(a), Self::Boolean(b)) => Self::Int(bi64(a) * bi64(b)),
1106            (Self::Boolean(a), Self::Int(b)) => Self::Int(bi64(a) * b),
1107            (Self::Boolean(a), Self::Float(b)) => Self::Float(bf64(a) * b),
1108            (Self::String(a), Self::Int(b)) => {
1109                Self::String(a.as_str().repeat(clamp(b, 0, i64::MAX) as usize).into())
1110            }
1111            _ => Self::NAN,
1112        }
1113    }
1114}
1115
1116impl Div for RantyValue {
1117    type Output = ValueResult<Self>;
1118    fn div(self, rhs: Self) -> Self::Output {
1119        Ok(match (self, rhs) {
1120            (Self::Nothing, _) | (_, Self::Nothing) => Self::Nothing,
1121            (_, Self::Int(0)) | (_, Self::Boolean(false)) => return Err(ValueError::DivideByZero),
1122            (Self::Int(a), Self::Int(b)) => Self::Int(a / b),
1123            (Self::Int(a), Self::Float(b)) => Self::Float((a as f64) / b),
1124            (Self::Int(a), Self::Boolean(b)) => Self::Int(a / bi64(b)),
1125            (Self::Float(a), Self::Float(b)) => Self::Float(a / b),
1126            (Self::Float(a), Self::Int(b)) => Self::Float(a / (b as f64)),
1127            (Self::Float(a), Self::Boolean(b)) => Self::Float(a / bf64(b)),
1128            (Self::Boolean(a), Self::Boolean(b)) => Self::Int(bi64(a) / bi64(b)),
1129            (Self::Boolean(a), Self::Int(b)) => Self::Int(bi64(a) / b),
1130            (Self::Boolean(a), Self::Float(b)) => Self::Float(bf64(a) / b),
1131            _ => Self::NAN,
1132        })
1133    }
1134}
1135
1136impl Rem for RantyValue {
1137    type Output = ValueResult<Self>;
1138    fn rem(self, rhs: Self) -> Self::Output {
1139        Ok(match (self, rhs) {
1140            (Self::Nothing, _) | (_, Self::Nothing) => Self::Nothing,
1141            (_, Self::Int(0)) | (_, Self::Boolean(false)) => return Err(ValueError::DivideByZero),
1142            (Self::Int(a), Self::Int(b)) => Self::Int(a % b),
1143            (Self::Int(a), Self::Float(b)) => Self::Float((a as f64) % b),
1144            (Self::Int(a), Self::Boolean(b)) => Self::Int(a % bi64(b)),
1145            _ => Self::NAN,
1146        })
1147    }
1148}
1149
1150impl RantyValue {
1151    /// Raises `self` to the `exponent` power.
1152    #[inline]
1153    pub fn pow(self, exponent: Self) -> ValueResult<Self> {
1154        match (self, exponent) {
1155            (Self::Int(lhs), Self::Int(rhs)) => {
1156                if rhs >= 0 {
1157                    cast::u32(rhs)
1158                        .map_err(|_| ValueError::Overflow)
1159                        .and_then(|rhs| lhs.checked_pow(rhs).ok_or(ValueError::Overflow))
1160                        .map(Self::Int)
1161                } else {
1162                    Ok(Self::Float((lhs as f64).powf(rhs as f64)))
1163                }
1164            }
1165            (Self::Int(lhs), Self::Float(rhs)) => Ok(Self::Float((lhs as f64).powf(rhs))),
1166            (Self::Float(lhs), Self::Int(rhs)) => Ok(Self::Float(lhs.powf(rhs as f64))),
1167            (Self::Float(lhs), Self::Float(rhs)) => Ok(Self::Float(lhs.powf(rhs))),
1168            _ => Ok(Self::Nothing),
1169        }
1170    }
1171
1172    /// Calculates the absolute value.
1173    #[inline]
1174    pub fn abs(self) -> ValueResult<Self> {
1175        match self {
1176            Self::Int(i) => i.checked_abs().map(Self::Int).ok_or(ValueError::Overflow),
1177            Self::Float(f) => Ok(Self::Float(f.abs())),
1178            _ => Ok(self),
1179        }
1180    }
1181
1182    /// Calculates the logical AND.
1183    #[inline]
1184    pub fn and(self, rhs: RantyValue) -> Self {
1185        let truth_lhs = self.to_bool();
1186        if !truth_lhs {
1187            self
1188        } else {
1189            rhs
1190        }
1191    }
1192
1193    /// Calculates the logical OR.
1194    #[inline]
1195    pub fn or(self, rhs: RantyValue) -> Self {
1196        let truth_lhs = self.to_bool();
1197        if truth_lhs {
1198            self
1199        } else {
1200            rhs
1201        }
1202    }
1203
1204    /// Calculates the logical XOR.
1205    #[inline]
1206    pub fn xor(self, rhs: RantyValue) -> Self {
1207        let truth_lhs = self.to_bool();
1208        let truth_rhs = rhs.to_bool();
1209        RantyValue::Boolean(truth_lhs ^ truth_rhs)
1210    }
1211}