1use std::{
2 collections::{BTreeMap, HashMap},
3 fmt::{Display, Write},
4 hash::{BuildHasher, Hash},
5};
6
7use serde::ser::{Serialize, SerializeMap, Serializer};
8
9use crate::{value_display_fmt, Basic, DynamicType, Error, Signature, Type, Value};
10
11#[derive(Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
18pub struct Dict<'k, 'v> {
19 map: BTreeMap<Value<'k>, Value<'v>>,
20 signature: Signature,
21}
22
23impl<'k, 'v> Dict<'k, 'v> {
24 pub fn new(key_signature: &Signature, value_signature: &Signature) -> Self {
26 let signature = Signature::dict(key_signature.clone(), value_signature.clone());
27
28 Self {
29 map: BTreeMap::new(),
30 signature,
31 }
32 }
33
34 pub fn append<'kv: 'k, 'vv: 'v>(
44 &mut self,
45 key: Value<'kv>,
46 value: Value<'vv>,
47 ) -> Result<(), Error> {
48 match &self.signature {
49 Signature::Dict { key: key_sig, .. }
50 if key.value_signature() != key_sig.signature() =>
51 {
52 return Err(Error::SignatureMismatch(
53 key.value_signature().clone(),
54 key_sig.signature().clone().to_string(),
55 ))
56 }
57 Signature::Dict {
58 value: value_sig, ..
59 } if value.value_signature() != value_sig.signature() => {
60 return Err(Error::SignatureMismatch(
61 value.value_signature().clone(),
62 value_sig.signature().clone().to_string(),
63 ))
64 }
65 Signature::Dict { .. } => (),
66 _ => unreachable!("Incorrect `Dict` signature"),
67 }
68
69 self.map.insert(key, value);
70
71 Ok(())
72 }
73
74 pub fn add<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
76 where
77 K: Basic + Into<Value<'k>> + Ord,
78 V: Into<Value<'v>> + DynamicType,
79 {
80 self.append(Value::new(key), Value::new(value))
81 }
82
83 pub fn get<'d, K, V>(&'d self, key: &'k K) -> Result<Option<V>, Error>
85 where
86 'd: 'k + 'v,
87 &'k K: TryInto<Value<'k>>,
88 <&'k K as TryInto<Value<'k>>>::Error: Into<crate::Error>,
89 V: TryFrom<&'v Value<'v>>,
90 <V as TryFrom<&'v Value<'v>>>::Error: Into<crate::Error>,
91 {
92 let key: Value<'_> = key.try_into().map_err(Into::into)?;
93
94 self.map.get(&key).map(|v| v.downcast_ref()).transpose()
95 }
96
97 pub fn signature(&self) -> &Signature {
99 &self.signature
100 }
101
102 pub(crate) fn try_to_owned(&self) -> crate::Result<Dict<'static, 'static>> {
103 Ok(Dict {
104 signature: self.signature.clone(),
105 map: self
106 .map
107 .iter()
108 .map(|(k, v)| {
109 Ok((
110 k.try_to_owned().map(Into::into)?,
111 v.try_to_owned().map(Into::into)?,
112 ))
113 })
114 .collect::<crate::Result<_>>()?,
115 })
116 }
117
118 pub(crate) fn try_into_owned(self) -> crate::Result<Dict<'static, 'static>> {
119 Ok(Dict {
120 signature: self.signature,
121 map: self
122 .map
123 .into_iter()
124 .map(|(k, v)| {
125 Ok((
126 k.try_into_owned().map(Into::into)?,
127 v.try_into_owned().map(Into::into)?,
128 ))
129 })
130 .collect::<crate::Result<_>>()?,
131 })
132 }
133
134 pub fn try_clone(&self) -> Result<Self, Error> {
136 let entries = self
137 .map
138 .iter()
139 .map(|(k, v)| Ok((k.try_clone()?, v.try_clone()?)))
140 .collect::<Result<_, crate::Error>>()?;
141
142 Ok(Self {
143 map: entries,
144 signature: self.signature.clone(),
145 })
146 }
147
148 pub(crate) fn new_full_signature(signature: &Signature) -> Self {
150 assert!(matches!(signature, Signature::Dict { .. }));
151
152 Self {
153 map: BTreeMap::new(),
154 signature: signature.clone(),
155 }
156 }
157
158 pub fn iter(&self) -> impl Iterator<Item = (&Value<'k>, &Value<'v>)> {
159 self.map.iter()
160 }
161
162 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Value<'k>, &mut Value<'v>)> {
163 self.map.iter_mut()
164 }
165
166 }
168
169impl Display for Dict<'_, '_> {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 dict_display_fmt(self, f, true)
172 }
173}
174
175impl<'k, 'v> IntoIterator for Dict<'k, 'v> {
176 type Item = (Value<'k>, Value<'v>);
177 type IntoIter = <BTreeMap<Value<'k>, Value<'v>> as IntoIterator>::IntoIter;
178
179 fn into_iter(self) -> Self::IntoIter {
180 self.map.into_iter()
181 }
182}
183
184pub(crate) fn dict_display_fmt(
185 dict: &Dict<'_, '_>,
186 f: &mut std::fmt::Formatter<'_>,
187 type_annotate: bool,
188) -> std::fmt::Result {
189 if dict.map.is_empty() {
190 if type_annotate {
191 write!(f, "@{} ", dict.signature())?;
192 }
193 f.write_str("{}")?;
194 } else {
195 f.write_char('{')?;
196
197 let mut type_annotate = type_annotate;
199
200 for (i, (key, value)) in dict.map.iter().enumerate() {
201 value_display_fmt(key, f, type_annotate)?;
202 f.write_str(": ")?;
203 value_display_fmt(value, f, type_annotate)?;
204 type_annotate = false;
205
206 if i + 1 < dict.map.len() {
207 f.write_str(", ")?;
208 }
209 }
210
211 f.write_char('}')?;
212 }
213
214 Ok(())
215}
216
217impl Serialize for Dict<'_, '_> {
218 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
219 where
220 S: Serializer,
221 {
222 let mut map = serializer.serialize_map(Some(self.map.len()))?;
223 for (key, value) in self.map.iter() {
224 key.serialize_value_as_dict_key(&mut map)?;
225 value.serialize_value_as_dict_value(&mut map)?;
226 }
227
228 map.end()
229 }
230}
231
232macro_rules! from_dict {
234 ($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident)*>) => {
235 impl<'k, 'v, K, V $(, $typaram)*> TryFrom<Dict<'k, 'v>> for $ty<K, V $(, $typaram)*>
236 where
237 K: Basic + TryFrom<Value<'k>> $(+ $kbound1 $(+ $kbound2)*)*,
238 V: TryFrom<Value<'v>>,
239 K::Error: Into<crate::Error>,
240 V::Error: Into<crate::Error>,
241 $($typaram: BuildHasher + Default,)*
242 {
243 type Error = Error;
244
245 fn try_from(v: Dict<'k, 'v>) -> Result<Self, Self::Error> {
246 v.map.into_iter().map(|(key, value)| {
247 let key = if let Value::Value(v) = key {
248 K::try_from(*v)
249 } else {
250 K::try_from(key)
251 }
252 .map_err(Into::into)?;
253
254 let value = if let Value::Value(v) = value {
255 V::try_from(*v)
256 } else {
257 V::try_from(value)
258 }
259 .map_err(Into::into)?;
260
261 Ok((key, value))
262 }).collect::<Result<_, _>>()
263 }
264 }
265 };
266}
267from_dict!(HashMap<K: Eq + Hash, V, H>);
268from_dict!(BTreeMap<K: Ord, V>);
269
270macro_rules! to_dict {
275 ($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident)*>) => {
276 impl<'k, 'v, K, V $(, $typaram)*> From<$ty<K, V $(, $typaram)*>> for Dict<'k, 'v>
277 where
278 K: Type + Into<Value<'k>>,
279 V: Type + Into<Value<'v>>,
280 $($typaram: BuildHasher,)*
281 {
282 fn from(value: $ty<K, V $(, $typaram)*>) -> Self {
283 let entries = value
284 .into_iter()
285 .map(|(key, value)| (Value::new(key), Value::new(value)))
286 .collect();
287 let key_signature = K::SIGNATURE.clone();
288 let value_signature = V::SIGNATURE.clone();
289 let signature = Signature::dict(key_signature, value_signature);
290
291 Self {
292 map: entries,
293 signature,
294 }
295 }
296 }
297 };
298}
299to_dict!(HashMap<K: Eq + Hash, V, H>);
300to_dict!(BTreeMap<K: Ord, V>);