Skip to main content

simple_expressions/types/
dict.rs

1use crate::types::coerce::Context;
2use crate::types::error::{Error, Result};
3use crate::types::object::Object;
4use crate::types::primitive::Primitive;
5use crate::types::value::Value;
6use crate::types::{function, list};
7
8use crate::types::function::method0;
9use std::any::Any;
10use std::collections::BTreeMap;
11use std::rc::Rc;
12
13pub fn new(map: BTreeMap<String, Value>) -> Value {
14    Value::Object(Rc::new(DictObject::new(map)))
15}
16pub fn new_string_dict(map: BTreeMap<String, String>) -> DictObject {
17    DictObject {
18        map: map.into_iter().map(|(k, v)| (k, Value::Primitive(Primitive::Str(v)))).collect(),
19    }
20}
21pub struct DictObject {
22    map: BTreeMap<String, Value>,
23}
24
25impl DictObject {
26    pub fn new(map: BTreeMap<String, Value>) -> DictObject {
27        DictObject { map }
28    }
29}
30
31impl Object for DictObject {
32    fn type_name(&self) -> &'static str {
33        "dict"
34    }
35    fn get_member(&self, name: &str) -> Result<Value> {
36        match name {
37            "length" => Ok(Value::from(self.map.len() as i64)),
38            "keys" => {
39                let keys: Vec<Value> = self.map.keys().cloned().map(Value::from).collect();
40                Ok(function::method0(move |_cx| Ok(list::new(keys.clone()))))
41            }
42            "values" => {
43                let vals: Vec<Value> = self.map.values().cloned().collect();
44                Ok(method0(move |_cx| Ok(list::new(vals.clone()))))
45            }
46            "contains" => {
47                let base = self.map.clone();
48                Ok(function::method1(move |arg: &Value, _cx: &Context| {
49                    if let Value::Primitive(Primitive::Str(s)) = arg {
50                        Ok(Value::from(base.contains_key(s)))
51                    } else {
52                        Err(Error::TypeMismatch("contains expects a string".into()))
53                    }
54                }))
55            }
56            "get" => {
57                let base = self.map.clone();
58                Ok(function::new(std::rc::Rc::new(move |args: &[Value], _cx: &Context| {
59                    if args.len() != 2 {
60                        return Err(Error::EvaluationFailed("expected 2 args".into()));
61                    }
62                    let key = match &args[0] {
63                        Value::Primitive(Primitive::Str(s)) => s.clone(),
64                        _ => return Err(Error::TypeMismatch("get expects string key".into())),
65                    };
66                    if let Some(v) = base.get(&key) { Ok(v.clone()) } else { Ok(args[1].clone()) }
67                })))
68            }
69            _ => Err(Error::UnknownMember {
70                type_name: "dict".into(),
71                member: name.to_string(),
72            }),
73        }
74    }
75
76    fn get_key_value(&self, key: &str) -> Result<Value> {
77        self.map.get(key).cloned().ok_or(Error::NoSuchKey(key.to_string()))
78    }
79
80    fn as_string(&self) -> Option<String> {
81        Some(format!("{{{}}}", self.map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::<Vec<_>>().join(", ")))
82    }
83
84    fn as_bool(&self) -> Option<bool> {
85        Some(!self.map.is_empty())
86    }
87
88    fn equals(&self, other: &Value) -> bool {
89        if let Value::Object(other_obj) = other
90            && let Some(other_dict) = other_obj.as_any().downcast_ref::<DictObject>()
91        {
92            self.map == other_dict.map
93        } else {
94            false
95        }
96    }
97
98    fn as_any(&self) -> &dyn Any {
99        self
100    }
101
102    fn as_any_mut(&mut self) -> &mut dyn Any {
103        self
104    }
105}