Skip to main content

ruma_common/profile/
profile_field_value_serde.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize, Serializer, de, ser::SerializeMap};
4
5use super::{CustomProfileFieldValue, ProfileFieldName, ProfileFieldValue};
6
7/// Helper type to deserialize [`ProfileFieldValue`].
8///
9/// If the field name is set, this will try to deserialize a map entry using this key, otherwise
10/// this will deserialize the first key-value pair encountered.
11pub struct ProfileFieldValueVisitor(Option<ProfileFieldName>);
12
13impl ProfileFieldValueVisitor {
14    /// Construct a `ProfileFieldValueVisitor` for the given optional field name.
15    pub fn new(field: Option<ProfileFieldName>) -> Self {
16        Self(field)
17    }
18
19    /// Try to find the key in the map matching the proper field name if it is set, or return the
20    /// first key if it is not set.
21    ///
22    /// Returns `Ok(Some(_))` if the field name was found, `Ok(None)` if it wasn't found, and
23    /// `Err(_)` if deserialization of a key failed.
24    fn find_field_name<'de, V>(self, map: &mut V) -> Result<Option<ProfileFieldName>, V::Error>
25    where
26        V: de::MapAccess<'de>,
27    {
28        while let Some(key) = map.next_key::<ProfileFieldName>()? {
29            if self.0.as_ref().is_none_or(|field| key == *field) {
30                return Ok(Some(key));
31            }
32        }
33
34        Ok(None)
35    }
36}
37
38impl<'de> de::Visitor<'de> for ProfileFieldValueVisitor {
39    type Value = Option<ProfileFieldValue>;
40
41    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42        formatter.write_str("enum ProfileFieldValue")
43    }
44
45    fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
46    where
47        V: de::MapAccess<'de>,
48    {
49        let Some(field) = self.find_field_name(&mut map)? else {
50            return Ok(None);
51        };
52
53        Ok(Some(match field {
54            ProfileFieldName::AvatarUrl => ProfileFieldValue::AvatarUrl(map.next_value()?),
55            ProfileFieldName::DisplayName => ProfileFieldValue::DisplayName(map.next_value()?),
56            ProfileFieldName::TimeZone => ProfileFieldValue::TimeZone(map.next_value()?),
57            ProfileFieldName::_Custom(field) => {
58                ProfileFieldValue::_Custom(CustomProfileFieldValue {
59                    field: field.0.into(),
60                    value: map.next_value()?,
61                })
62            }
63        }))
64    }
65}
66
67impl<'de> Deserialize<'de> for ProfileFieldValue {
68    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
69    where
70        D: de::Deserializer<'de>,
71    {
72        deserializer
73            .deserialize_map(ProfileFieldValueVisitor(None))?
74            .ok_or_else(|| de::Error::invalid_length(0, &"at least one key-value pair"))
75    }
76}
77
78impl Serialize for CustomProfileFieldValue {
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: Serializer,
82    {
83        let mut map = serializer.serialize_map(Some(1))?;
84        map.serialize_entry(&self.field, &self.value)?;
85        map.end()
86    }
87}