1 use std::{collections::HashMap, convert::TryFrom, hash::BuildHasher};
2 
3 use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
4 use static_assertions::assert_impl_all;
5 
6 use crate::{Basic, DynamicType, Error, Signature, Type, Value};
7 
8 /// A helper type to wrap dictionaries in a [`Value`].
9 ///
10 /// API is provided to convert from, and to a [`HashMap`].
11 ///
12 /// [`Value`]: enum.Value.html#variant.Dict
13 /// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
14 #[derive(Debug, Clone, PartialEq)]
15 pub struct Dict<'k, 'v> {
16     entries: Vec<DictEntry<'k, 'v>>,
17     key_signature: Signature<'k>,
18     value_signature: Signature<'v>,
19     // should use a separate lifetime or everything should use the same but API break.
20     signature: Signature<'k>,
21 }
22 
23 assert_impl_all!(Dict<'_, '_>: Send, Sync, Unpin);
24 
25 impl<'k, 'v> Dict<'k, 'v> {
26     /// Create a new empty `Dict`, given the signature of the keys and values.
new(key_signature: Signature<'k>, value_signature: Signature<'v>) -> Self27     pub fn new(key_signature: Signature<'k>, value_signature: Signature<'v>) -> Self {
28         let signature = create_signature(&key_signature, &value_signature);
29 
30         Self {
31             entries: vec![],
32             key_signature,
33             value_signature,
34             signature,
35         }
36     }
37 
38     /// Append `key` and `value` as a new entry.
39     ///
40     /// # Errors
41     ///
42     /// * if [`key.value_signature()`] doesn't match the key signature `self` was created for.
43     /// * if [`value.value_signature()`] doesn't match the value signature `self` was created for.
44     ///
45     /// [`key.value_signature()`]: enum.Value.html#method.value_signature
46     /// [`value.value_signature()`]: enum.Value.html#method.value_signature
append<'kv: 'k, 'vv: 'v>( &mut self, key: Value<'kv>, value: Value<'vv>, ) -> Result<(), Error>47     pub fn append<'kv: 'k, 'vv: 'v>(
48         &mut self,
49         key: Value<'kv>,
50         value: Value<'vv>,
51     ) -> Result<(), Error> {
52         check_child_value_signature!(self.key_signature, key.value_signature(), "key");
53         check_child_value_signature!(self.value_signature, value.value_signature(), "value");
54 
55         self.entries.push(DictEntry { key, value });
56 
57         Ok(())
58     }
59 
60     /// Add a new entry.
add<K, V>(&mut self, key: K, value: V) -> Result<(), Error> where K: Basic + Into<Value<'k>> + std::hash::Hash + std::cmp::Eq, V: Into<Value<'v>> + DynamicType,61     pub fn add<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
62     where
63         K: Basic + Into<Value<'k>> + std::hash::Hash + std::cmp::Eq,
64         V: Into<Value<'v>> + DynamicType,
65     {
66         check_child_value_signature!(self.key_signature, K::signature(), "key");
67         check_child_value_signature!(self.value_signature, value.dynamic_signature(), "value");
68 
69         self.entries.push(DictEntry {
70             key: Value::new(key),
71             value: Value::new(value),
72         });
73 
74         Ok(())
75     }
76 
77     /// Get the value for the given key.
get<'d, K, V>(&'d self, key: &K) -> Result<Option<&'v V>, Error> where 'd: 'k + 'v, K: ?Sized + std::cmp::Eq + 'k, V: ?Sized, &'k K: TryFrom<&'k Value<'k>>, &'v V: TryFrom<&'v Value<'v>>,78     pub fn get<'d, K, V>(&'d self, key: &K) -> Result<Option<&'v V>, Error>
79     where
80         'd: 'k + 'v,
81         K: ?Sized + std::cmp::Eq + 'k,
82         V: ?Sized,
83         &'k K: TryFrom<&'k Value<'k>>,
84         &'v V: TryFrom<&'v Value<'v>>,
85     {
86         for entry in &self.entries {
87             let entry_key = entry.key.downcast_ref::<K>().ok_or(Error::IncorrectType)?;
88             if *entry_key == *key {
89                 return entry
90                     .value
91                     .downcast_ref()
92                     .ok_or(Error::IncorrectType)
93                     .map(Some);
94             }
95         }
96 
97         Ok(None)
98     }
99 
100     /// Get the signature of this `Dict`.
101     ///
102     /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to
103     /// avoid that.
104     ///
105     /// [`full_signature`]: #method.full_signature
signature(&self) -> Signature<'static>106     pub fn signature(&self) -> Signature<'static> {
107         self.signature.to_owned()
108     }
109 
110     /// Get the signature of this `Dict`.
full_signature(&self) -> &Signature<'_>111     pub fn full_signature(&self) -> &Signature<'_> {
112         &self.signature
113     }
114 
to_owned(&self) -> Dict<'static, 'static>115     pub(crate) fn to_owned(&self) -> Dict<'static, 'static> {
116         Dict {
117             key_signature: self.key_signature.to_owned(),
118             value_signature: self.value_signature.to_owned(),
119             signature: self.signature.to_owned(),
120             entries: self.entries.iter().map(|v| v.to_owned()).collect(),
121         }
122     }
123 
124     /// Create a new empty `Dict`, given the complete signature.
new_full_signature<'s: 'k + 'v>(signature: Signature<'s>) -> Self125     pub(crate) fn new_full_signature<'s: 'k + 'v>(signature: Signature<'s>) -> Self {
126         let key_signature = signature.slice(2..3);
127         let value_signature = signature.slice(3..signature.len() - 1);
128 
129         Self {
130             entries: vec![],
131             key_signature,
132             value_signature,
133             signature,
134         }
135     }
136 
137     // TODO: Provide more API like https://docs.rs/toml/0.5.5/toml/map/struct.Map.html
138 }
139 
140 impl<'k, 'v> Serialize for Dict<'k, 'v> {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,141     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
142     where
143         S: Serializer,
144     {
145         let mut seq = serializer.serialize_seq(Some(self.entries.len()))?;
146         for entry in &self.entries {
147             seq.serialize_element(entry)?;
148         }
149 
150         seq.end()
151     }
152 }
153 
154 // Conversion of Dict to HashMap
155 impl<'k, 'v, K, V, H> TryFrom<Dict<'k, 'v>> for HashMap<K, V, H>
156 where
157     K: Basic + TryFrom<Value<'k>> + std::hash::Hash + std::cmp::Eq,
158     V: TryFrom<Value<'v>>,
159     H: BuildHasher + Default,
160     K::Error: Into<crate::Error>,
161     V::Error: Into<crate::Error>,
162 {
163     type Error = Error;
164 
try_from(v: Dict<'k, 'v>) -> Result<Self, Self::Error>165     fn try_from(v: Dict<'k, 'v>) -> Result<Self, Self::Error> {
166         let mut map = HashMap::default();
167         for e in v.entries.into_iter() {
168             let key = if let Value::Value(v) = e.key {
169                 K::try_from(*v)
170             } else {
171                 K::try_from(e.key)
172             }
173             .map_err(Into::into)?;
174 
175             let value = if let Value::Value(v) = e.value {
176                 V::try_from(*v)
177             } else {
178                 V::try_from(e.value)
179             }
180             .map_err(Into::into)?;
181 
182             map.insert(key, value);
183         }
184         Ok(map)
185     }
186 }
187 
188 // TODO: this could be useful
189 // impl<'d, 'k, 'v, K, V, H> TryFrom<&'d Dict<'k, 'v>> for HashMap<&'k K, &'v V, H>
190 
191 // Conversion of Hashmap to Dict
192 impl<'k, 'v, K, V, H> From<HashMap<K, V, H>> for Dict<'k, 'v>
193 where
194     K: Type + Into<Value<'k>> + std::hash::Hash + std::cmp::Eq,
195     V: Type + Into<Value<'v>>,
196     H: BuildHasher + Default,
197 {
from(value: HashMap<K, V, H>) -> Self198     fn from(value: HashMap<K, V, H>) -> Self {
199         let entries = value
200             .into_iter()
201             .map(|(key, value)| DictEntry {
202                 key: Value::new(key),
203                 value: Value::new(value),
204             })
205             .collect();
206         let key_signature = K::signature();
207         let value_signature = V::signature();
208         let signature = create_signature(&key_signature, &value_signature);
209 
210         Self {
211             entries,
212             key_signature,
213             value_signature,
214             signature,
215         }
216     }
217 }
218 
219 // TODO: Conversion of Dict from/to BTreeMap
220 
221 #[derive(Debug, Clone, PartialEq)]
222 struct DictEntry<'k, 'v> {
223     key: Value<'k>,
224     value: Value<'v>,
225 }
226 
227 impl<'k, 'v> DictEntry<'k, 'v> {
to_owned(&self) -> DictEntry<'static, 'static>228     fn to_owned(&self) -> DictEntry<'static, 'static> {
229         DictEntry {
230             key: self.key.to_owned(),
231             value: self.value.to_owned(),
232         }
233     }
234 }
235 
236 impl<'k, 'v> Serialize for DictEntry<'k, 'v> {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,237     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238     where
239         S: Serializer,
240     {
241         let mut entry = serializer.serialize_struct("zvariant::DictEntry", 2)?;
242         self.key
243             .serialize_value_as_struct_field("zvariant::DictEntry::Key", &mut entry)?;
244         self.value
245             .serialize_value_as_struct_field("zvariant::DictEntry::Value", &mut entry)?;
246 
247         entry.end()
248     }
249 }
250 
create_signature( key_signature: &Signature<'_>, value_signature: &Signature<'_>, ) -> Signature<'static>251 fn create_signature(
252     key_signature: &Signature<'_>,
253     value_signature: &Signature<'_>,
254 ) -> Signature<'static> {
255     Signature::from_string_unchecked(format!("a{{{}{}}}", key_signature, value_signature,))
256 }
257