hass_entity_state/attributes/
serde.rs

1use super::{AttributeKey, AttributeValue, Attributes};
2use crate::EntityState;
3use serde::{de::MapAccess, ser::SerializeMap, Deserialize, Serialize};
4use std::{collections::BTreeMap, fmt, marker::PhantomData};
5
6impl<'a, K, V, E> Serialize for Attributes<'a, K, V, E>
7where
8  K: AttributeKey<'a>,
9  V: AttributeValue<'a>,
10  E: EntityState<'a, K, V>,
11{
12  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
13  where
14    S: serde::Serializer,
15  {
16    let mut map = serializer.serialize_map(Some(self.0.len()))?;
17    for (key, value) in self.0.iter() {
18      map.serialize_entry(key.borrow(), value.borrow())?;
19    }
20    map.end()
21  }
22}
23
24struct AttributesVisitor<'a, K, V, E>
25where
26  K: AttributeKey<'a>,
27  V: AttributeValue<'a>,
28  E: EntityState<'a, K, V>,
29{
30  marker: PhantomData<Attributes<'a, K, V, E>>,
31}
32
33impl<'a, 'de: 'a, K, V, E> serde::de::Visitor<'de> for AttributesVisitor<'a, K, V, E>
34where
35  K: AttributeKey<'a> + 'a,
36  V: AttributeValue<'a> + 'a,
37  E: EntityState<'a, K, V>,
38{
39  type Value = Attributes<'a, K, V, E>;
40
41  fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
42    formatter.write_str("a map")
43  }
44
45  #[inline]
46  fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
47  where
48    A: MapAccess<'de>,
49  {
50    // TODO: Object pool?
51    let mut values = BTreeMap::new();
52
53    while let Some((AttributeKeyWrapper { value: key, .. }, AttributeValueWrapper { value, .. })) =
54      map.next_entry()?
55    {
56      values.insert(key, value);
57    }
58
59    Ok(Attributes(values, PhantomData))
60  }
61}
62
63impl<'a, 'de: 'a, K, V, E> Deserialize<'de> for Attributes<'a, K, V, E>
64where
65  K: AttributeKey<'a> + 'a,
66  V: AttributeValue<'a> + 'a,
67  E: EntityState<'a, K, V>,
68{
69  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
70  where
71    D: serde::Deserializer<'de>,
72  {
73    deserializer.deserialize_map(AttributesVisitor {
74      marker: PhantomData,
75    })
76  }
77}
78
79struct AttributeKeyWrapper<'a, K> {
80  value: K,
81  marker: PhantomData<&'a ()>,
82}
83struct AttributeKeyVisitor<'a, K> {
84  marker: PhantomData<fn() -> &'a K>,
85}
86impl<'a, 'de: 'a, K> serde::de::Visitor<'de> for AttributeKeyVisitor<'a, K>
87where
88  K: AttributeKey<'a>,
89{
90  type Value = AttributeKeyWrapper<'a, K>;
91
92  fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
93    formatter.write_str("a string")
94  }
95
96  // Borrowed directly from the input string, which has lifetime 'de
97  // The input must outlive the resulting Cow.
98  fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
99  where
100    E: serde::de::Error,
101  {
102    Ok(AttributeKeyWrapper {
103      value: K::from_cow(std::borrow::Cow::Borrowed(value)),
104      marker: PhantomData,
105    })
106  }
107
108  // A string that currently only lives in a temporary buffer -- we need a copy
109  // (Example: serde is reading from a BufRead)
110  fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
111  where
112    E: serde::de::Error,
113  {
114    Ok(AttributeKeyWrapper {
115      value: K::from_cow(std::borrow::Cow::Owned(value.to_owned())),
116      marker: PhantomData,
117    })
118  }
119
120  // An optimisation of visit_str for situations where the deserializer has
121  // already taken ownership. For example, the string contains escaped characters.
122  fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
123  where
124    E: serde::de::Error,
125  {
126    Ok(AttributeKeyWrapper {
127      value: K::from_cow(std::borrow::Cow::Owned(value)),
128      marker: PhantomData,
129    })
130  }
131}
132impl<'a, 'de: 'a, K: 'a> Deserialize<'de> for AttributeKeyWrapper<'a, K>
133where
134  K: AttributeKey<'a>,
135{
136  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
137  where
138    D: serde::Deserializer<'de>,
139  {
140    deserializer.deserialize_str(AttributeKeyVisitor {
141      marker: PhantomData,
142    })
143  }
144}
145
146struct AttributeValueWrapper<'a, V> {
147  value: V,
148  marker: PhantomData<&'a ()>,
149}
150struct AttributeValueVisitor<'a, V> {
151  marker: PhantomData<fn() -> &'a V>,
152}
153impl<'a, 'de: 'a, V> serde::de::Visitor<'de> for AttributeValueVisitor<'a, V>
154where
155  V: AttributeValue<'a>,
156{
157  type Value = AttributeValueWrapper<'a, V>;
158
159  fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
160    formatter.write_str("a string")
161  }
162
163  // Borrowed directly from the input string, which has lifetime 'de
164  // The input must outlive the resulting Cow.
165  fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
166  where
167    E: serde::de::Error,
168  {
169    Ok(AttributeValueWrapper {
170      value: V::from_cow(std::borrow::Cow::Borrowed(value)),
171      marker: PhantomData,
172    })
173  }
174
175  // A string that currently only lives in a temporary buffer -- we need a copy
176  // (Example: serde is reading from a BufRead)
177  fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
178  where
179    E: serde::de::Error,
180  {
181    Ok(AttributeValueWrapper {
182      value: V::from_cow(std::borrow::Cow::Owned(value.to_owned())),
183      marker: PhantomData,
184    })
185  }
186
187  // An optimisation of visit_str for situations where the deserializer has
188  // already taken ownership. For example, the string contains escaped characters.
189  fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
190  where
191    E: serde::de::Error,
192  {
193    Ok(AttributeValueWrapper {
194      value: V::from_cow(std::borrow::Cow::Owned(value)),
195      marker: PhantomData,
196    })
197  }
198}
199
200impl<'a, 'de: 'a, V: 'a> Deserialize<'de> for AttributeValueWrapper<'a, V>
201where
202  V: AttributeValue<'a>,
203{
204  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
205  where
206    D: serde::Deserializer<'de>,
207  {
208    deserializer.deserialize_str(AttributeValueVisitor {
209      marker: PhantomData,
210    })
211  }
212}
213
214#[cfg(test)]
215mod tests {
216  use std::borrow::Cow;
217
218  use assert_matches::assert_matches;
219
220  use crate::EntityStateValue;
221
222  use super::*;
223  use serde_test::{assert_tokens, Token};
224
225  struct FakeEntityType;
226  impl EntityStateValue for FakeEntityType {}
227  impl<'a> EntityState<'a, Cow<'a, str>, Cow<'a, str>> for FakeEntityType {
228    type State = FakeEntityType;
229
230    fn get(&self) -> &Self::State {
231      todo!()
232    }
233
234    fn get_mut(&mut self) -> &mut Self::State {
235      todo!()
236    }
237
238    fn attributes(&self) -> &Attributes<'a, Cow<'a, str>, Cow<'a, str>, Self> {
239      todo!()
240    }
241
242    fn attributes_mut(&mut self) -> &mut Attributes<'a, Cow<'a, str>, Cow<'a, str>, Self> {
243      todo!()
244    }
245  }
246
247  #[test]
248  fn serde() {
249    let mut attributes: Attributes<Cow<str>, Cow<str>, FakeEntityType> = Attributes::default();
250    attributes.insert(Cow::Borrowed("k1"), Cow::Borrowed("v1"));
251    attributes.insert(Cow::Borrowed("k2"), Cow::Borrowed("v2"));
252
253    assert_tokens(
254      &attributes,
255      &[
256        Token::Map { len: Some(2) },
257        Token::Str("k1"),
258        Token::Str("v1"),
259        Token::Str("k2"),
260        Token::Str("v2"),
261        Token::MapEnd,
262      ],
263    )
264  }
265
266  #[test]
267  fn json_borrows() {
268    let json = r#"{"k1":"v1","k2":"v2"}"#;
269    let attributes: Attributes<Cow<str>, Cow<str>, FakeEntityType> =
270      serde_json::from_str(json).expect("should parse");
271
272    assert_matches!(attributes.get_inner("k1"), Some(Cow::Borrowed("v1")));
273    assert_matches!(attributes.get_inner("k2"), Some(Cow::Borrowed("v2")));
274  }
275}