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