1 | use std::{ |
2 | collections::{BTreeMap, HashMap}, |
3 | fmt::{Display, Write}, |
4 | hash::{BuildHasher, Hash}, |
5 | }; |
6 | |
7 | use serde::ser::{Serialize, SerializeMap, Serializer}; |
8 | use static_assertions::assert_impl_all; |
9 | |
10 | use crate::{value_display_fmt, Basic, DynamicType, Error, Signature, Type, Value}; |
11 | |
12 | /// A helper type to wrap dictionaries in a [`Value`]. |
13 | /// |
14 | /// API is provided to convert from, and to a [`HashMap`]. |
15 | /// |
16 | /// [`Value`]: enum.Value.html#variant.Dict |
17 | /// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html |
18 | #[derive (Debug, Hash, PartialEq, PartialOrd, Eq, Ord)] |
19 | pub struct Dict<'k, 'v> { |
20 | map: BTreeMap<Value<'k>, Value<'v>>, |
21 | key_signature: Signature<'k>, |
22 | value_signature: Signature<'v>, |
23 | // should use a separate lifetime or everything should use the same but API break. |
24 | signature: Signature<'k>, |
25 | } |
26 | |
27 | assert_impl_all!(Dict<'_, '_>: Send, Sync, Unpin); |
28 | |
29 | impl<'k, 'v> Dict<'k, 'v> { |
30 | /// Create a new empty `Dict`, given the signature of the keys and values. |
31 | pub fn new(key_signature: Signature<'k>, value_signature: Signature<'v>) -> Self { |
32 | let signature = create_signature(&key_signature, &value_signature); |
33 | |
34 | Self { |
35 | map: BTreeMap::new(), |
36 | key_signature, |
37 | value_signature, |
38 | signature, |
39 | } |
40 | } |
41 | |
42 | /// Append `key` and `value` as a new entry. |
43 | /// |
44 | /// # Errors |
45 | /// |
46 | /// * if [`key.value_signature()`] doesn't match the key signature `self` was created for. |
47 | /// * if [`value.value_signature()`] doesn't match the value signature `self` was created for. |
48 | /// |
49 | /// [`key.value_signature()`]: enum.Value.html#method.value_signature |
50 | /// [`value.value_signature()`]: enum.Value.html#method.value_signature |
51 | pub fn append<'kv: 'k, 'vv: 'v>( |
52 | &mut self, |
53 | key: Value<'kv>, |
54 | value: Value<'vv>, |
55 | ) -> Result<(), Error> { |
56 | check_child_value_signature!(self.key_signature, key.value_signature(), "key" ); |
57 | check_child_value_signature!(self.value_signature, value.value_signature(), "value" ); |
58 | |
59 | self.map.insert(key, value); |
60 | |
61 | Ok(()) |
62 | } |
63 | |
64 | /// Add a new entry. |
65 | pub fn add<K, V>(&mut self, key: K, value: V) -> Result<(), Error> |
66 | where |
67 | K: Basic + Into<Value<'k>> + Ord, |
68 | V: Into<Value<'v>> + DynamicType, |
69 | { |
70 | check_child_value_signature!(self.key_signature, K::signature(), "key" ); |
71 | check_child_value_signature!(self.value_signature, value.dynamic_signature(), "value" ); |
72 | |
73 | self.map.insert(Value::new(key), Value::new(value)); |
74 | |
75 | Ok(()) |
76 | } |
77 | |
78 | /// Get the value for the given key. |
79 | pub fn get<'d, K, V>(&'d self, key: &'k K) -> Result<Option<V>, Error> |
80 | where |
81 | 'd: 'k + 'v, |
82 | &'k K: TryInto<Value<'k>>, |
83 | <&'k K as TryInto<Value<'k>>>::Error: Into<crate::Error>, |
84 | V: TryFrom<&'v Value<'v>>, |
85 | <V as TryFrom<&'v Value<'v>>>::Error: Into<crate::Error>, |
86 | { |
87 | let key: Value<'_> = key.try_into().map_err(Into::into)?; |
88 | |
89 | self.map.get(&key).map(|v| v.downcast_ref()).transpose() |
90 | } |
91 | |
92 | /// Get the signature of this `Dict`. |
93 | /// |
94 | /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to |
95 | /// avoid that. |
96 | /// |
97 | /// [`full_signature`]: #method.full_signature |
98 | pub fn signature(&self) -> Signature<'static> { |
99 | self.signature.to_owned() |
100 | } |
101 | |
102 | /// Get the signature of this `Dict`. |
103 | pub fn full_signature(&self) -> &Signature<'_> { |
104 | &self.signature |
105 | } |
106 | |
107 | pub(crate) fn try_to_owned(&self) -> crate::Result<Dict<'static, 'static>> { |
108 | Ok(Dict { |
109 | key_signature: self.key_signature.to_owned(), |
110 | value_signature: self.value_signature.to_owned(), |
111 | signature: self.signature.to_owned(), |
112 | map: self |
113 | .map |
114 | .iter() |
115 | .map(|(k, v)| { |
116 | Ok(( |
117 | k.try_to_owned().map(Into::into)?, |
118 | v.try_to_owned().map(Into::into)?, |
119 | )) |
120 | }) |
121 | .collect::<crate::Result<_>>()?, |
122 | }) |
123 | } |
124 | |
125 | /// Try to clone the `Dict`. |
126 | pub fn try_clone(&self) -> Result<Self, Error> { |
127 | let entries = self |
128 | .map |
129 | .iter() |
130 | .map(|(k, v)| Ok((k.try_clone()?, v.try_clone()?))) |
131 | .collect::<Result<_, crate::Error>>()?; |
132 | |
133 | Ok(Self { |
134 | map: entries, |
135 | key_signature: self.key_signature.clone(), |
136 | value_signature: self.value_signature.clone(), |
137 | signature: self.signature.clone(), |
138 | }) |
139 | } |
140 | |
141 | /// Create a new empty `Dict`, given the complete signature. |
142 | pub(crate) fn new_full_signature<'s: 'k + 'v>(signature: Signature<'s>) -> Self { |
143 | let key_signature = signature.slice(2..3); |
144 | let value_signature = signature.slice(3..signature.len() - 1); |
145 | |
146 | Self { |
147 | map: BTreeMap::new(), |
148 | key_signature, |
149 | value_signature, |
150 | signature, |
151 | } |
152 | } |
153 | |
154 | pub fn iter(&self) -> impl Iterator<Item = (&Value<'k>, &Value<'v>)> { |
155 | self.map.iter() |
156 | } |
157 | |
158 | pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Value<'k>, &mut Value<'v>)> { |
159 | self.map.iter_mut() |
160 | } |
161 | |
162 | // TODO: Provide more API like https://docs.rs/toml/0.5.5/toml/map/struct.Map.html |
163 | } |
164 | |
165 | impl Display for Dict<'_, '_> { |
166 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
167 | dict_display_fmt(self, f, type_annotate:true) |
168 | } |
169 | } |
170 | |
171 | impl<'k, 'v> IntoIterator for Dict<'k, 'v> { |
172 | type Item = (Value<'k>, Value<'v>); |
173 | type IntoIter = <BTreeMap<Value<'k>, Value<'v>> as IntoIterator>::IntoIter; |
174 | |
175 | fn into_iter(self) -> Self::IntoIter { |
176 | self.map.into_iter() |
177 | } |
178 | } |
179 | |
180 | pub(crate) fn dict_display_fmt( |
181 | dict: &Dict<'_, '_>, |
182 | f: &mut std::fmt::Formatter<'_>, |
183 | type_annotate: bool, |
184 | ) -> std::fmt::Result { |
185 | if dict.map.is_empty() { |
186 | if type_annotate { |
187 | write!(f, "@ {} " , dict.full_signature())?; |
188 | } |
189 | f.write_str("{}" )?; |
190 | } else { |
191 | f.write_char('{' )?; |
192 | |
193 | // Annotate only the first entry as the rest will be of the same type. |
194 | let mut type_annotate = type_annotate; |
195 | |
196 | for (i, (key, value)) in dict.map.iter().enumerate() { |
197 | value_display_fmt(key, f, type_annotate)?; |
198 | f.write_str(": " )?; |
199 | value_display_fmt(value, f, type_annotate)?; |
200 | type_annotate = false; |
201 | |
202 | if i + 1 < dict.map.len() { |
203 | f.write_str(", " )?; |
204 | } |
205 | } |
206 | |
207 | f.write_char('}' )?; |
208 | } |
209 | |
210 | Ok(()) |
211 | } |
212 | |
213 | impl<'k, 'v> Serialize for Dict<'k, 'v> { |
214 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
215 | where |
216 | S: Serializer, |
217 | { |
218 | let mut map: ::SerializeMap = serializer.serialize_map(len:Some(self.map.len()))?; |
219 | for (key: &Value<'k>, value: &Value<'v>) in self.map.iter() { |
220 | key.serialize_value_as_dict_key(&mut map)?; |
221 | value.serialize_value_as_dict_value(&mut map)?; |
222 | } |
223 | |
224 | map.end() |
225 | } |
226 | } |
227 | |
228 | // Conversion of Dict to Map types |
229 | macro_rules! from_dict { |
230 | ($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident)*>) => { |
231 | impl<'k, 'v, K, V $(, $typaram)*> TryFrom<Dict<'k, 'v>> for $ty<K, V $(, $typaram)*> |
232 | where |
233 | K: Basic + TryFrom<Value<'k>> $(+ $kbound1 $(+ $kbound2)*)*, |
234 | V: TryFrom<Value<'v>>, |
235 | K::Error: Into<crate::Error>, |
236 | V::Error: Into<crate::Error>, |
237 | $($typaram: BuildHasher + Default,)* |
238 | { |
239 | type Error = Error; |
240 | |
241 | fn try_from(v: Dict<'k, 'v>) -> Result<Self, Self::Error> { |
242 | v.map.into_iter().map(|(key, value)| { |
243 | let key = if let Value::Value(v) = key { |
244 | K::try_from(*v) |
245 | } else { |
246 | K::try_from(key) |
247 | } |
248 | .map_err(Into::into)?; |
249 | |
250 | let value = if let Value::Value(v) = value { |
251 | V::try_from(*v) |
252 | } else { |
253 | V::try_from(value) |
254 | } |
255 | .map_err(Into::into)?; |
256 | |
257 | Ok((key, value)) |
258 | }).collect::<Result<_, _>>() |
259 | } |
260 | } |
261 | }; |
262 | } |
263 | from_dict!(HashMap<K: Eq + Hash, V, H>); |
264 | from_dict!(BTreeMap<K: Ord, V>); |
265 | |
266 | // TODO: this could be useful |
267 | // impl<'d, 'k, 'v, K, V, H> TryFrom<&'d Dict<'k, 'v>> for HashMap<&'k K, &'v V, H> |
268 | |
269 | // Conversion of Hashmap to Dict |
270 | macro_rules! to_dict { |
271 | ($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident)*>) => { |
272 | impl<'k, 'v, K, V $(, $typaram)*> From<$ty<K, V $(, $typaram)*>> for Dict<'k, 'v> |
273 | where |
274 | K: Type + Into<Value<'k>>, |
275 | V: Type + Into<Value<'v>>, |
276 | $($typaram: BuildHasher,)* |
277 | { |
278 | fn from(value: $ty<K, V $(, $typaram)*>) -> Self { |
279 | let entries = value |
280 | .into_iter() |
281 | .map(|(key, value)| (Value::new(key), Value::new(value))) |
282 | .collect(); |
283 | let key_signature = K::signature(); |
284 | let value_signature = V::signature(); |
285 | let signature = create_signature(&key_signature, &value_signature); |
286 | |
287 | Self { |
288 | map: entries, |
289 | key_signature, |
290 | value_signature, |
291 | signature, |
292 | } |
293 | } |
294 | } |
295 | }; |
296 | } |
297 | to_dict!(HashMap<K: Eq + Hash, V, H>); |
298 | to_dict!(BTreeMap<K: Ord, V>); |
299 | |
300 | fn create_signature( |
301 | key_signature: &Signature<'_>, |
302 | value_signature: &Signature<'_>, |
303 | ) -> Signature<'static> { |
304 | Signature::from_string_unchecked(signature:format!("a {{{key_signature}{value_signature}}}" ,)) |
305 | } |
306 | |