arithmetic_eval/values/
object.rs1use core::{
4 fmt,
5 iter::{self, FromIterator},
6 ops,
7};
8
9use crate::{
10 alloc::{hash_map, HashMap, String},
11 Value,
12};
13
14#[derive(Debug, Clone, PartialEq)]
41pub struct Object<T> {
42 fields: HashMap<String, Value<T>>,
43}
44
45impl<T> From<Object<T>> for Value<T> {
46 fn from(object: Object<T>) -> Self {
47 Self::Object(object)
48 }
49}
50
51impl<T> Default for Object<T> {
52 fn default() -> Self {
53 Self {
54 fields: HashMap::new(),
55 }
56 }
57}
58
59impl<T: fmt::Display> fmt::Display for Object<T> {
60 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61 formatter.write_str("#{ ")?;
62 for (i, (name, value)) in self.iter().enumerate() {
63 write!(formatter, "{name}: {value}")?;
64 if i + 1 < self.len() {
65 write!(formatter, ", ")?;
66 } else {
67 write!(formatter, " ")?;
68 }
69 }
70 formatter.write_str("}")
71 }
72}
73
74impl<T> Object<T> {
75 pub fn just(field_name: impl Into<String>, value: Value<T>) -> Self {
77 let fields = iter::once((field_name.into(), value)).collect();
78 Self { fields }
79 }
80
81 pub fn len(&self) -> usize {
83 self.fields.len()
84 }
85
86 pub fn is_empty(&self) -> bool {
88 self.fields.is_empty()
89 }
90
91 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value<T>)> + '_ {
93 self.fields
94 .iter()
95 .map(|(name, value)| (name.as_str(), value))
96 }
97
98 pub fn field_names(&self) -> impl Iterator<Item = &str> + '_ {
100 self.fields.keys().map(String::as_str)
101 }
102
103 pub fn get(&self, field_name: &str) -> Option<&Value<T>> {
106 self.fields.get(field_name)
107 }
108
109 pub fn contains_field(&self, field_name: &str) -> bool {
111 self.fields.contains_key(field_name)
112 }
113
114 pub fn insert(&mut self, field_name: impl Into<String>, value: Value<T>) -> Option<Value<T>> {
116 self.fields.insert(field_name.into(), value)
117 }
118
119 pub fn remove(&mut self, field_name: &str) -> Option<Value<T>> {
121 self.fields.remove(field_name)
122 }
123}
124
125impl<T> ops::Index<&str> for Object<T> {
126 type Output = Value<T>;
127
128 fn index(&self, index: &str) -> &Self::Output {
129 &self.fields[index]
130 }
131}
132
133impl<T> IntoIterator for Object<T> {
134 type Item = (String, Value<T>);
135 type IntoIter = hash_map::IntoIter<String, Value<T>>;
137
138 fn into_iter(self) -> Self::IntoIter {
139 self.fields.into_iter()
140 }
141}
142
143impl<'r, T> IntoIterator for &'r Object<T> {
144 type Item = (&'r str, &'r Value<T>);
145 type IntoIter = Iter<'r, T>;
147
148 fn into_iter(self) -> Self::IntoIter {
149 self.fields
150 .iter()
151 .map(|(name, value)| (name.as_str(), value))
152 }
153}
154
155pub type Iter<'r, T> = iter::Map<
156 hash_map::Iter<'r, String, Value<T>>,
157 fn((&'r String, &'r Value<T>)) -> (&'r str, &'r Value<T>),
158>;
159
160impl<T, S, V> FromIterator<(S, V)> for Object<T>
161where
162 S: Into<String>,
163 V: Into<Value<T>>,
164{
165 fn from_iter<I: IntoIterator<Item = (S, V)>>(iter: I) -> Self {
166 Self {
167 fields: iter
168 .into_iter()
169 .map(|(name, value)| (name.into(), value.into()))
170 .collect(),
171 }
172 }
173}
174
175impl<T, S, V> Extend<(S, V)> for Object<T>
176where
177 S: Into<String>,
178 V: Into<Value<T>>,
179{
180 fn extend<I: IntoIterator<Item = (S, V)>>(&mut self, iter: I) {
181 let new_fields = iter
182 .into_iter()
183 .map(|(name, value)| (name.into(), value.into()));
184 self.fields.extend(new_fields);
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn object_to_string() {
194 let mut obj = Object::<f32>::default();
195 let obj_string = obj.to_string();
196 assert_eq!(obj_string, "#{ }");
197
198 obj.insert("x", Value::Prim(3.0));
199 let obj_string = obj.to_string();
200 assert_eq!(obj_string, "#{ x: 3 }");
201
202 obj.insert("y", Value::Prim(4.0));
203 let obj_string = obj.to_string();
204 assert!(
205 obj_string == "#{ x: 3, y: 4 }" || obj_string == "#{ y: 4, x: 3 }",
206 "Unexpected obj_string: {obj_string}"
207 );
208 }
209}