ruma_common/
serde.rs

1//! (De)serialization helpers for other Ruma crates.
2//!
3//! Part of that is a fork of [serde_urlencoded], with support for sequences in `Deserialize` /
4//! `Serialize` structs (e.g. `Vec<Something>`) that are (de)serialized as `field=val1&field=val2`.
5//!
6//! [serde_urlencoded]: https://github.com/nox/serde_urlencoded
7
8use std::{fmt, marker::PhantomData};
9
10use serde::{
11    de::{self, DeserializeOwned, SeqAccess, Visitor},
12    Deserialize, Deserializer,
13};
14use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
15use tracing::debug;
16
17pub mod base64;
18mod buf;
19pub mod can_be_empty;
20mod cow;
21pub mod duration;
22pub mod json_string;
23mod raw;
24pub mod single_element_seq;
25mod strings;
26pub mod test;
27
28pub use self::{
29    base64::{Base64, Base64DecodeError},
30    buf::{json_to_buf, slice_to_buf},
31    can_be_empty::{is_empty, CanBeEmpty},
32    cow::deserialize_cow_str,
33    raw::Raw,
34    strings::{
35        btreemap_deserialize_v1_powerlevel_values, deserialize_as_number_or_string,
36        deserialize_as_optional_number_or_string, deserialize_v1_powerlevel, empty_string_as_none,
37        none_as_empty_string,
38    },
39};
40
41/// The inner type of [`JsonValue::Object`].
42pub type JsonObject = serde_json::Map<String, JsonValue>;
43
44/// Check whether a value is equal to its default value.
45pub fn is_default<T: Default + PartialEq>(val: &T) -> bool {
46    *val == T::default()
47}
48
49/// Deserialize a `T` via `Option<T>`, falling back to `T::default()`.
50pub fn none_as_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
51where
52    D: Deserializer<'de>,
53    T: Default + Deserialize<'de>,
54{
55    Ok(Option::deserialize(deserializer)?.unwrap_or_default())
56}
57
58/// Simply returns `true`.
59///
60/// Useful for `#[serde(default = ...)]`.
61pub fn default_true() -> bool {
62    true
63}
64
65/// Simply dereferences the given bool.
66///
67/// Useful for `#[serde(skip_serializing_if = ...)]`.
68#[allow(clippy::trivially_copy_pass_by_ref)]
69pub fn is_true(b: &bool) -> bool {
70    *b
71}
72
73/// Helper function for `serde_json::value::RawValue` deserialization.
74pub fn from_raw_json_value<'a, T, E>(val: &'a RawJsonValue) -> Result<T, E>
75where
76    T: Deserialize<'a>,
77    E: de::Error,
78{
79    serde_json::from_str(val.get()).map_err(E::custom)
80}
81
82/// Helper function for returning a default value if deserialization of the type fails.
83///
84/// Assumes that the content being deserialized is JSON.
85///
86/// Used as `#[serde(deserialize_with = "default_on_error")]`.
87pub fn default_on_error<'de, D, T>(deserializer: D) -> Result<T, D::Error>
88where
89    D: Deserializer<'de>,
90    T: DeserializeOwned + Default,
91{
92    let value = match Box::<RawJsonValue>::deserialize(deserializer) {
93        Ok(value) => value,
94        Err(error) => {
95            debug!("deserialization error, using default value: {error}");
96            return Ok(T::default());
97        }
98    };
99
100    Ok(from_raw_json_value(&value).unwrap_or_else(|error: D::Error| {
101        debug!("deserialization error, using default value: {error}");
102        T::default()
103    }))
104}
105
106/// Helper function for ignoring invalid items in a `Vec`, instead letting them cause the entire
107/// `Vec` to fail deserialization
108pub fn ignore_invalid_vec_items<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
109where
110    D: Deserializer<'de>,
111    T: Deserialize<'de>,
112{
113    struct SkipInvalid<T>(PhantomData<T>);
114
115    impl<'de, T> Visitor<'de> for SkipInvalid<T>
116    where
117        T: Deserialize<'de>,
118    {
119        type Value = Vec<T>;
120
121        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122            formatter.write_str("Vec with possibly invalid items")
123        }
124
125        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
126        where
127            A: SeqAccess<'de>,
128        {
129            let mut vec = Vec::new();
130
131            while let Some(result) = seq.next_element::<T>().transpose() {
132                let Ok(elem) = result else {
133                    continue;
134                };
135
136                vec.push(elem);
137            }
138
139            Ok(vec)
140        }
141    }
142
143    deserializer.deserialize_seq(SkipInvalid(PhantomData))
144}
145
146pub use ruma_macros::{
147    AsRefStr, AsStrAsRefStr, DebugAsRefStr, DeserializeFromCowStr, DisplayAsRefStr, FromString,
148    OrdAsRefStr, PartialEqAsRefStr, PartialOrdAsRefStr, SerializeAsRefStr, StringEnum,
149    _FakeDeriveSerde,
150};