stainless_script/
object.rs

1use crate::class::Class;
2use std::{
3    cmp::Ordering,
4    error::Error,
5    fmt::{Debug, Display},
6    rc::Rc,
7    str::FromStr,
8};
9
10/// Types that implement FromStr should use their FromStr implementation. Other types should use
11/// ron (<https://github.com/ron-rs/ron>)
12pub trait ObjectFromStr {
13    fn from_str(s: &str) -> Result<Rc<dyn Object>, Box<dyn Error + Send + Sync>>
14    where
15        Self: Sized;
16}
17
18impl<T: 'static + FromStr + Object> ObjectFromStr for T
19where
20    T::Err: 'static + Error + Send + Sync,
21{
22    fn from_str(s: &str) -> Result<Rc<dyn Object>, Box<dyn Error + Send + Sync>> {
23        <Self as FromStr>::from_str(s)
24            .map_err(Into::into)
25            .map(|o| Rc::new(o) as Rc<dyn Object>)
26    }
27}
28
29/// Stainless Script Object version of [`PartialEq`]
30pub trait ObjectPartialEq {
31    fn eq(&self, other: Rc<dyn Object>) -> bool;
32    fn ne(&self, other: Rc<dyn Object>) -> bool {
33        !self.eq(other)
34    }
35}
36
37/// Stainless Script Object version of [`PartialOrd`]
38pub trait ObjectPartialOrd {
39    fn partial_cmp(&self, other: Rc<dyn Object>) -> Option<Ordering>;
40    fn lt(&self, other: Rc<dyn Object>) -> bool {
41        matches!(self.partial_cmp(other), Some(Ordering::Less))
42    }
43    fn le(&self, other: Rc<dyn Object>) -> bool {
44        matches!(
45            self.partial_cmp(other),
46            Some(Ordering::Less | Ordering::Equal)
47        )
48    }
49    fn gt(&self, other: Rc<dyn Object>) -> bool {
50        matches!(self.partial_cmp(other), Some(Ordering::Greater))
51    }
52    fn ge(&self, other: Rc<dyn Object>) -> bool {
53        matches!(
54            self.partial_cmp(other),
55            Some(Ordering::Greater | Ordering::Equal)
56        )
57    }
58}
59
60/// Stainless Script Object version of [`Eq`]
61pub trait ObjectEq: ObjectPartialEq {}
62
63/// Stainless Script Object version of [`Ord`]
64pub trait ObjectOrd: ObjectEq + ObjectPartialOrd {
65    fn cmp(&self, other: Rc<dyn Object>) -> Ordering;
66}
67
68/// The object of a data type. Data type is derived from the object's class. Methods specified here
69/// are for use in nodes mostly.
70pub trait Object:
71    Display + Debug + ObjectFromStr + ObjectPartialEq + ObjectPartialOrd + ObjectEq + ObjectOrd
72{
73    fn class(&self) -> Class;
74    /// Since Object requires Display, this has little use and is implemented  through ToString,
75    /// which is implemented for all types implementing Display. Left for consistency with
76    /// as_number and other methods
77    fn as_string(&self) -> String {
78        self.to_string()
79    }
80    /// Convert to number
81    fn as_number(&self) -> f64;
82    /// Convert to boolean
83    fn as_bool(&self) -> bool;
84    /// Suggested implementation: Have a `HashMap<String, Rc<dyn Object>>` to manage fields.
85    /// Default implementation is `unimplemented!()` because most types don't have fields.
86    fn get_field(&self, _field: Rc<dyn Object>) -> Rc<dyn Object> {
87        unimplemented!()
88    }
89    /// Suggested implementation: use `String::from` to convert `&str` to `String` and use that as
90    /// insertion key. Default implementation is `unimplemented!()` because most types don't have
91    /// fields.
92    fn set_field(&mut self, _field: Rc<dyn Object>, _value: Rc<dyn Object>) {
93        unimplemented!()
94    }
95
96    fn cast_to(&self, to: &Class) -> Rc<dyn Object> {
97        if self.class().name == "any" {
98            (to.obj_from_str.unwrap())(&self.as_string()).unwrap()
99        } else {
100            unimplemented!()
101        }
102    }
103}