use std::{ clone::Clone, fmt::{self, Debug, Formatter}, marker::PhantomData, }; use serde::{ de::{Deserialize, DeserializeOwned, Deserializer}, ser::{Serialize, Serializer}, }; use serde_json::value::RawValue; /// A wrapper around `Box`, to be used in place of any type in the Matrix endpoint /// definition to allow request and response types to contain that said type represented by /// the generic argument `Ev`. /// /// Ruma offers the `Raw` wrapper to enable passing around JSON text that is only partially /// validated. This is useful when a client receives events that do not follow the spec perfectly /// or a server needs to generate reference hashes with the original canonical JSON string. /// All event structs and enums implement `Serialize` / `Deserialize`, `Raw` should be used /// to pass around events in a lossless way. /// /// ```ignore /// let json = r#"{ "type": "imagine a full event", "content": {...} }"#; /// /// let deser = serde_json::from_str::>(json) /// .unwrap() // the first Result from serde_json::from_str, will not fail /// .deserialize() // deserialize to the inner type /// .unwrap(); // finally get to the AnyRoomEvent /// ``` pub struct Raw { json: Box, _ev: PhantomData, } impl Raw { fn new(json: Box) -> Self { Self { json, _ev: PhantomData } } /// Create a `Raw` from a boxed `RawValue`. pub fn from_json(raw: Box) -> Self { Self::new(raw) } /// Access the underlying json value. pub fn json(&self) -> &RawValue { &self.json } /// Convert `self` into the underlying json value. pub fn into_json(self) -> Box { self.json } } impl Raw where T: DeserializeOwned, { /// Try to deserialize the JSON into the expected type. pub fn deserialize(&self) -> Result { serde_json::from_str(self.json.get()) } } impl From<&T> for Raw { fn from(val: &T) -> Self { Self::new(serde_json::value::to_raw_value(val).unwrap()) } } // With specialization a fast path from impl for `impl From From for Raw { fn from(val: T) -> Self { Self::from(&val) } } impl Clone for Raw { fn clone(&self) -> Self { Self::new(self.json.clone()) } } impl Debug for Raw { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { use std::any::type_name; f.debug_struct(&format!("Raw::<{}>", type_name::())).field("json", &self.json).finish() } } impl<'de, T> Deserialize<'de> for Raw { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Box::::deserialize(deserializer).map(Self::new) } } impl Serialize for Raw { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.json.serialize(serializer) } }