ruma_federation_api/serde/
pdu_process_response.rs

1use std::collections::BTreeMap;
2
3use ruma_common::OwnedEventId;
4#[cfg(feature = "client")]
5use serde::de::{Deserializer, MapAccess, Visitor};
6#[cfg(feature = "server")]
7use serde::ser::{SerializeMap, Serializer};
8
9#[cfg_attr(feature = "client", derive(serde::Deserialize))]
10#[cfg_attr(feature = "server", derive(serde::Serialize))]
11struct WrappedError {
12    #[cfg_attr(feature = "server", serde(skip_serializing_if = "Option::is_none"))]
13    error: Option<String>,
14}
15
16#[cfg(feature = "server")]
17pub(crate) fn serialize<S>(
18    response: &BTreeMap<OwnedEventId, Result<(), String>>,
19    serializer: S,
20) -> Result<S::Ok, S::Error>
21where
22    S: Serializer,
23{
24    let mut map = serializer.serialize_map(Some(response.len()))?;
25    for (key, value) in response {
26        let wrapped_error = WrappedError { error: value.clone().err() };
27        map.serialize_entry(&key, &wrapped_error)?;
28    }
29    map.end()
30}
31
32#[cfg(feature = "client")]
33#[allow(clippy::type_complexity)]
34pub(crate) fn deserialize<'de, D>(
35    deserializer: D,
36) -> Result<BTreeMap<OwnedEventId, Result<(), String>>, D::Error>
37where
38    D: Deserializer<'de>,
39{
40    use std::fmt;
41
42    struct PduProcessResponseVisitor;
43
44    impl<'de> Visitor<'de> for PduProcessResponseVisitor {
45        type Value = BTreeMap<OwnedEventId, Result<(), String>>;
46
47        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
48            formatter.write_str("A map of EventIds to a map of optional errors")
49        }
50
51        fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
52        where
53            M: MapAccess<'de>,
54        {
55            let mut map = BTreeMap::new();
56
57            while let Some((key, value)) = access.next_entry::<OwnedEventId, WrappedError>()? {
58                let v = match value.error {
59                    None => Ok(()),
60                    Some(error) => Err(error),
61                };
62                map.insert(key, v);
63            }
64            Ok(map)
65        }
66    }
67
68    deserializer.deserialize_map(PduProcessResponseVisitor)
69}
70
71#[cfg(all(test, feature = "client"))]
72mod tests_client {
73    use ruma_common::event_id;
74    use serde_json::json;
75
76    use super::deserialize;
77
78    #[test]
79    fn deserialize_error() {
80        let json = json!({
81            "$someevent:matrix.org": { "error": "Some processing error." }
82        });
83
84        let response = deserialize(json).unwrap();
85        let event_id = event_id!("$someevent:matrix.org");
86
87        let event_response = response.get(event_id).unwrap().clone().unwrap_err();
88        assert_eq!(event_response, "Some processing error.");
89    }
90
91    #[test]
92    fn deserialize_null_error_is_ok() {
93        let json = json!({
94            "$someevent:matrix.org": { "error": null }
95        });
96
97        let response = deserialize(json).unwrap();
98        let event_id = event_id!("$someevent:matrix.org");
99
100        response.get(event_id).unwrap().as_ref().unwrap();
101    }
102
103    #[test]
104    fn deserialize_empty_error_is_err() {
105        let json = json!({
106            "$someevent:matrix.org": { "error": "" }
107        });
108
109        let response = deserialize(json).unwrap();
110        let event_id = event_id!("$someevent:matrix.org");
111
112        let event_response = response.get(event_id).unwrap().clone().unwrap_err();
113        assert_eq!(event_response, "");
114    }
115
116    #[test]
117    fn deserialize_ok() {
118        let json = json!({
119            "$someevent:matrix.org": {}
120        });
121        let response = deserialize(json).unwrap();
122        response.get(event_id!("$someevent:matrix.org")).unwrap().as_ref().unwrap();
123    }
124}
125
126#[cfg(all(test, feature = "server"))]
127mod tests_server {
128    use std::collections::BTreeMap;
129
130    use ruma_common::{OwnedEventId, owned_event_id};
131    use serde_json::{json, value::Serializer as JsonSerializer};
132
133    use super::serialize;
134
135    #[test]
136    fn serialize_error() {
137        let mut response: BTreeMap<OwnedEventId, Result<(), String>> = BTreeMap::new();
138        response
139            .insert(owned_event_id!("$someevent:matrix.org"), Err("Some processing error.".into()));
140
141        let serialized = serialize(&response, JsonSerializer).unwrap();
142        let json = json!({
143            "$someevent:matrix.org": { "error": "Some processing error." }
144        });
145        assert_eq!(serialized, json);
146    }
147
148    #[test]
149    fn serialize_ok() {
150        let mut response: BTreeMap<OwnedEventId, Result<(), String>> = BTreeMap::new();
151        response.insert(owned_event_id!("$someevent:matrix.org"), Ok(()));
152
153        let serialized = serialize(&response, serde_json::value::Serializer).unwrap();
154        let json = json!({
155            "$someevent:matrix.org": {}
156        });
157        assert_eq!(serialized, json);
158    }
159}