datex_core/values/core_values/
object.rs

1use super::super::core_value_trait::CoreValueTrait;
2use crate::values::traits::structural_eq::StructuralEq;
3use crate::values::value_container::ValueContainer;
4use indexmap::IndexMap;
5use indexmap::map::{IntoIter, Iter};
6use std::collections::HashMap;
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::iter::zip;
10
11#[derive(Clone, Debug, Default, Eq, PartialEq)]
12pub struct Object(pub IndexMap<String, ValueContainer>);
13impl Object {
14    pub fn new() -> Self {
15        Object(IndexMap::new())
16    }
17    pub fn size(&self) -> usize {
18        self.0.len()
19    }
20    pub fn get(&self, key: &str) -> &ValueContainer {
21        self.try_get(key)
22            .unwrap_or_else(|| panic!("Key '{key}' not found in Object"))
23    }
24    pub fn try_get(&self, key: &str) -> Option<&ValueContainer> {
25        self.0.get(key)
26    }
27    pub fn get_or_insert_with<F>(
28        &mut self,
29        key: &str,
30        default: F,
31    ) -> &mut ValueContainer
32    where
33        F: FnOnce() -> ValueContainer,
34    {
35        self.0.entry(key.to_string()).or_insert_with(default)
36    }
37    pub fn get_mut(&mut self, key: &str) -> Option<&mut ValueContainer> {
38        self.0.get_mut(key)
39    }
40    pub fn contains_key(&self, key: &str) -> bool {
41        self.0.contains_key(key)
42    }
43    pub fn keys(&self) -> impl Iterator<Item = &String> {
44        self.0.keys()
45    }
46    pub fn values(&self) -> impl Iterator<Item = &ValueContainer> {
47        self.0.values()
48    }
49    pub fn iter(&self) -> impl Iterator<Item = (&String, &ValueContainer)> {
50        self.0.iter()
51    }
52    pub fn iter_mut(
53        &mut self,
54    ) -> impl Iterator<Item = (&String, &mut ValueContainer)> {
55        self.0.iter_mut()
56    }
57    pub fn clear(&mut self) {
58        self.0.clear();
59    }
60    pub fn is_empty(&self) -> bool {
61        self.0.is_empty()
62    }
63
64    pub fn set<T: Into<ValueContainer>>(&mut self, key: &str, value: T) {
65        self.0.insert(key.to_string(), value.into());
66    }
67
68    pub fn remove(&mut self, key: &str) -> Option<ValueContainer> {
69        self.0.shift_remove(key)
70    }
71}
72
73impl StructuralEq for Object {
74    fn structural_eq(&self, other: &Self) -> bool {
75        if self.size() != other.size() {
76            return false;
77        }
78        // fixme #121: key order should not matter
79        for (key, value) in zip(self.0.iter(), other.0.iter()) {
80            if key.0 != value.0 || !key.1.structural_eq(value.1) {
81                return false;
82            }
83        }
84        true
85    }
86}
87
88impl Hash for Object {
89    fn hash<H: Hasher>(&self, state: &mut H) {
90        for (k, v) in &self.0 {
91            // fixme #122: sort keys to ensure consistent hashing
92            k.hash(state);
93            v.hash(state);
94        }
95    }
96}
97
98impl CoreValueTrait for Object {}
99
100impl fmt::Display for Object {
101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102        write!(f, "{{")?;
103        for (i, (key, value)) in self.0.iter().enumerate() {
104            if i > 0 {
105                write!(f, ", ")?;
106            }
107            write!(f, "\"{key}\": {value}")?;
108        }
109        write!(f, "}}")
110    }
111}
112
113impl<T> From<HashMap<String, T>> for Object
114where
115    T: Into<ValueContainer>,
116{
117    fn from(map: HashMap<String, T>) -> Self {
118        Object(map.into_iter().map(|(k, v)| (k, v.into())).collect())
119    }
120}
121
122impl<T> FromIterator<(String, T)> for Object
123where
124    T: Into<ValueContainer>,
125{
126    fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Self {
127        Object(iter.into_iter().map(|(k, v)| (k, v.into())).collect())
128    }
129}
130
131impl IntoIterator for Object {
132    type Item = (String, ValueContainer);
133    type IntoIter = IntoIter<String, ValueContainer>;
134
135    fn into_iter(self) -> Self::IntoIter {
136        self.0.into_iter()
137    }
138}
139
140impl<'a> IntoIterator for &'a Object {
141    type Item = (&'a String, &'a ValueContainer);
142    type IntoIter = Iter<'a, String, ValueContainer>;
143
144    fn into_iter(self) -> Self::IntoIter {
145        self.0.iter()
146    }
147}
148
149impl From<IndexMap<ValueContainer, ValueContainer>> for Object {
150    fn from(map: IndexMap<ValueContainer, ValueContainer>) -> Self {
151        Object(map.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
152    }
153}