ruma_serde/
raw.rs

1use std::{
2    clone::Clone,
3    fmt::{self, Debug, Formatter},
4    marker::PhantomData,
5    mem,
6};
7
8use serde::{
9    de::{Deserialize, Deserializer, IgnoredAny, MapAccess, Visitor},
10    ser::{Serialize, Serializer},
11};
12use serde_json::value::{to_raw_value as to_raw_json_value, RawValue as RawJsonValue};
13
14use crate::cow::MyCowStr;
15
16/// A wrapper around `Box<RawValue>`, to be used in place of any type in the Matrix endpoint
17/// definition to allow request and response types to contain that said type represented by
18/// the generic argument `Ev`.
19///
20/// Ruma offers the `Raw` wrapper to enable passing around JSON text that is only partially
21/// validated. This is useful when a client receives events that do not follow the spec perfectly
22/// or a server needs to generate reference hashes with the original canonical JSON string.
23/// All event structs and enums implement `Serialize` / `Deserialize`, `Raw` should be used
24/// to pass around events in a lossless way.
25///
26/// ```no_run
27/// # use serde::Deserialize;
28/// # use ruma_serde::Raw;
29/// # #[derive(Deserialize)]
30/// # struct AnyRoomEvent;
31///
32/// let json = r#"{ "type": "imagine a full event", "content": {...} }"#;
33///
34/// let deser = serde_json::from_str::<Raw<AnyRoomEvent>>(json)
35///     .unwrap() // the first Result from serde_json::from_str, will not fail
36///     .deserialize() // deserialize to the inner type
37///     .unwrap(); // finally get to the AnyRoomEvent
38/// ```
39#[repr(transparent)]
40pub struct Raw<T> {
41    json: Box<RawJsonValue>,
42    _ev: PhantomData<T>,
43}
44
45impl<T> Raw<T> {
46    /// Create a `Raw` by serializing the given `T`.
47    ///
48    /// Shorthand for `serde_json::value::to_raw_value(val).map(Raw::from_json)`, but specialized to
49    /// `T`.
50    ///
51    /// # Errors
52    ///
53    /// Fails if `T`s [`Serialize`] implementation fails.
54    pub fn new(val: &T) -> serde_json::Result<Self>
55    where
56        T: Serialize,
57    {
58        to_raw_json_value(val).map(Self::from_json)
59    }
60
61    /// Create a `Raw` from a boxed `RawValue`.
62    pub fn from_json(json: Box<RawJsonValue>) -> Self {
63        Self { json, _ev: PhantomData }
64    }
65
66    /// Access the underlying json value.
67    pub fn json(&self) -> &RawJsonValue {
68        &self.json
69    }
70
71    /// Convert `self` into the underlying json value.
72    pub fn into_json(self) -> Box<RawJsonValue> {
73        self.json
74    }
75
76    /// Try to access a given field inside this `Raw`, assuming it contains an object.
77    ///
78    /// Returns `Err(_)` when the contained value is not an object, or the field exists but is fails
79    /// to deserialize to the expected type.
80    ///
81    /// Returns `Ok(None)` when the field doesn't exist or is `null`.
82    ///
83    /// # Example
84    ///
85    /// ```no_run
86    /// # type CustomMatrixEvent = ();
87    /// # fn foo() -> serde_json::Result<()> {
88    /// # let raw_event: ruma_serde::Raw<()> = todo!();
89    /// if raw_event.get_field::<String>("type")?.as_deref() == Some("org.custom.matrix.event") {
90    ///     let event = raw_event.deserialize_as::<CustomMatrixEvent>()?;
91    ///     // ...
92    /// }
93    /// # Ok(())
94    /// # }
95    /// ```
96    pub fn get_field<'a, U>(&'a self, field_name: &str) -> serde_json::Result<Option<U>>
97    where
98        U: Deserialize<'a>,
99    {
100        struct SingleFieldVisitor<'b, T> {
101            field_name: &'b str,
102            _phantom: PhantomData<T>,
103        }
104
105        impl<'b, T> SingleFieldVisitor<'b, T> {
106            fn new(field_name: &'b str) -> Self {
107                Self { field_name, _phantom: PhantomData }
108            }
109        }
110
111        impl<'b, 'de, T> Visitor<'de> for SingleFieldVisitor<'b, T>
112        where
113            T: Deserialize<'de>,
114        {
115            type Value = Option<T>;
116
117            fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
118                formatter.write_str("a string")
119            }
120
121            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
122            where
123                A: MapAccess<'de>,
124            {
125                let mut res = None;
126                while let Some(key) = map.next_key::<MyCowStr<'_>>()? {
127                    if key.get() == self.field_name {
128                        res = Some(map.next_value()?);
129                    } else {
130                        map.next_value::<IgnoredAny>()?;
131                    }
132                }
133
134                Ok(res)
135            }
136        }
137
138        let mut deserializer = serde_json::Deserializer::from_str(self.json().get());
139        deserializer.deserialize_map(SingleFieldVisitor::new(field_name))
140    }
141
142    /// Try to deserialize the JSON as the expected type.
143    pub fn deserialize<'a>(&'a self) -> serde_json::Result<T>
144    where
145        T: Deserialize<'a>,
146    {
147        serde_json::from_str(self.json.get())
148    }
149
150    /// Try to deserialize the JSON as a custom type.
151    pub fn deserialize_as<'a, U>(&'a self) -> serde_json::Result<U>
152    where
153        U: Deserialize<'a>,
154    {
155        serde_json::from_str(self.json.get())
156    }
157
158    /// Turns `Raw<T>` into `Raw<U>` without changing the underlying JSON.
159    ///
160    /// This is useful for turning raw specific event types into raw event enum types.
161    pub fn cast<U>(self) -> Raw<U> {
162        Raw::from_json(self.into_json())
163    }
164
165    /// Turns `&Raw<T>` into `&Raw<U>` without changing the underlying JSON.
166    ///
167    /// This is useful for turning raw specific event types into raw event enum types.
168    pub fn cast_ref<U>(&self) -> &Raw<U> {
169        unsafe { mem::transmute(self) }
170    }
171}
172
173impl<T> Clone for Raw<T> {
174    fn clone(&self) -> Self {
175        Self::from_json(self.json.clone())
176    }
177}
178
179impl<T> Debug for Raw<T> {
180    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
181        use std::any::type_name;
182        f.debug_struct(&format!("Raw::<{}>", type_name::<T>())).field("json", &self.json).finish()
183    }
184}
185
186impl<'de, T> Deserialize<'de> for Raw<T> {
187    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
188    where
189        D: Deserializer<'de>,
190    {
191        Box::<RawJsonValue>::deserialize(deserializer).map(Self::from_json)
192    }
193}
194
195impl<T> Serialize for Raw<T> {
196    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
197    where
198        S: Serializer,
199    {
200        self.json.serialize(serializer)
201    }
202}