ruma_client_api/profile/
profile_field_serde.rs

1use std::{borrow::Cow, fmt, marker::PhantomData};
2
3use serde::{de, ser::SerializeMap, Deserialize, Serialize, Serializer};
4
5use super::{CustomProfileFieldValue, ProfileFieldName, ProfileFieldValue, StaticProfileField};
6
7/// Helper type to deserialize any type that implements [`StaticProfileField`].
8pub(super) struct StaticProfileFieldVisitor<F: StaticProfileField>(pub(super) PhantomData<F>);
9
10impl<'de, F: StaticProfileField> de::Visitor<'de> for StaticProfileFieldVisitor<F> {
11    type Value = Option<F::Value>;
12
13    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
14        write!(formatter, "a map with optional key `{}` and value", F::NAME)
15    }
16
17    fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
18    where
19        V: de::MapAccess<'de>,
20    {
21        let mut found = false;
22
23        while let Some(key) = map.next_key::<Cow<'_, str>>()? {
24            if key == F::NAME {
25                found = true;
26                break;
27            }
28        }
29
30        if !found {
31            return Ok(None);
32        }
33
34        Ok(Some(map.next_value()?))
35    }
36}
37
38impl Serialize for CustomProfileFieldValue {
39    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
40    where
41        S: Serializer,
42    {
43        let mut map = serializer.serialize_map(Some(1))?;
44        map.serialize_entry(&self.field, &self.value)?;
45        map.end()
46    }
47}
48
49/// Helper type to deserialize [`ProfileFieldValue`].
50///
51/// If the inner value is set, this will try to deserialize a map entry using this key, otherwise
52/// this will deserialize the first key-value pair encountered.
53pub(super) struct ProfileFieldValueVisitor(pub(super) Option<ProfileFieldName>);
54
55#[cfg(feature = "unstable-msc4133")]
56impl<'de> de::Visitor<'de> for ProfileFieldValueVisitor {
57    type Value = Option<ProfileFieldValue>;
58
59    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60        formatter.write_str("enum ProfileFieldValue")
61    }
62
63    fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
64    where
65        V: de::MapAccess<'de>,
66    {
67        let field = if let Some(field) = self.0 {
68            let mut found = false;
69
70            while let Some(key) = map.next_key::<ProfileFieldName>()? {
71                if key == field {
72                    found = true;
73                    break;
74                }
75            }
76
77            if !found {
78                return Ok(None);
79            }
80
81            field
82        } else {
83            let Some(field) = map.next_key()? else {
84                return Ok(None);
85            };
86
87            field
88        };
89
90        Ok(Some(match field {
91            ProfileFieldName::AvatarUrl => ProfileFieldValue::AvatarUrl(map.next_value()?),
92            ProfileFieldName::DisplayName => ProfileFieldValue::DisplayName(map.next_value()?),
93            ProfileFieldName::_Custom(field) => {
94                ProfileFieldValue::_Custom(CustomProfileFieldValue {
95                    field: field.0.into(),
96                    value: map.next_value()?,
97                })
98            }
99        }))
100    }
101}
102
103pub(super) fn deserialize_profile_field_value_option<'de, D>(
104    deserializer: D,
105) -> Result<Option<ProfileFieldValue>, D::Error>
106where
107    D: de::Deserializer<'de>,
108{
109    deserializer.deserialize_map(ProfileFieldValueVisitor(None))
110}
111
112impl<'de> Deserialize<'de> for ProfileFieldValue {
113    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114    where
115        D: de::Deserializer<'de>,
116    {
117        deserialize_profile_field_value_option(deserializer)?
118            .ok_or_else(|| de::Error::invalid_length(0, &"at least one key-value pair"))
119    }
120}