diff --git a/src/lib.rs b/src/lib.rs index 6d66ea1d..0d209cf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,6 +254,7 @@ pub trait EventResultCompatible: Sized { fn try_from_raw(_: Self::Raw) -> Result; } +// TODO: Replace with ! once that is stable /// An empty type #[derive(Debug)] pub enum Void {} @@ -335,14 +336,15 @@ where } } -impl Serialize for EventResult { +// For now, we don't support serialization of EventResult. +// This is going to be added in a future version. +/*impl Serialize for EventResult { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - unimplemented!() } -} +}*/ /// An error when attempting to create a value from a string via the `FromStr` trait. /// @@ -889,12 +891,13 @@ mod vec_as_map_of_empty { use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{collections::HashMap, hash::Hash}; + #[allow(clippy::ptr_arg)] pub fn serialize(vec: &Vec, serializer: S) -> Result where S: Serializer, T: Serialize + Hash + Eq, { - vec.into_iter() + vec.iter() .map(|v| (v, Empty)) .collect::>() .serialize(serializer) diff --git a/src/stripped.rs b/src/stripped.rs index cff76865..6d5b3a17 100644 --- a/src/stripped.rs +++ b/src/stripped.rs @@ -6,7 +6,8 @@ //! the other fields are otherwise inapplicable. use ruma_identifiers::UserId; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer}; +use serde_json::Value; use crate::{ room::{ @@ -67,6 +68,7 @@ pub struct StrippedStateContent { /// Data specific to the event type. pub content: C, + // FIXME(jplatte): It's unclear to me why this is stored /// The type of the event. #[serde(rename = "type")] pub event_type: EventType, @@ -119,7 +121,34 @@ impl EventResultCompatible for StrippedState { type Err = String; fn try_from_raw(raw: raw::StrippedState) -> Result { - unimplemented!() + use raw::StrippedState::*; + + fn convert( + raw_variant: fn(T::Raw) -> raw::StrippedState, + variant: fn(T) -> StrippedState, + raw: T::Raw, + ) -> Result { + T::try_from_raw(raw) + .map(variant) + .map_err(|(msg, raw)| (msg.into(), raw_variant(raw))) + } + + match raw { + RoomAliases(c) => convert(RoomAliases, Self::RoomAliases, c), + RoomAvatar(c) => convert(RoomAvatar, Self::RoomAvatar, c), + RoomCanonicalAlias(c) => convert(RoomCanonicalAlias, Self::RoomCanonicalAlias, c), + RoomCreate(c) => convert(RoomCreate, Self::RoomCreate, c), + RoomGuestAccess(c) => convert(RoomGuestAccess, Self::RoomGuestAccess, c), + RoomHistoryVisibility(c) => { + convert(RoomHistoryVisibility, Self::RoomHistoryVisibility, c) + } + RoomJoinRules(c) => convert(RoomJoinRules, Self::RoomJoinRules, c), + RoomMember(c) => convert(RoomMember, Self::RoomMember, c), + RoomName(c) => convert(RoomName, Self::RoomName, c), + RoomPowerLevels(c) => convert(RoomPowerLevels, Self::RoomPowerLevels, c), + RoomThirdPartyInvite(c) => convert(RoomThirdPartyInvite, Self::RoomThirdPartyInvite, c), + RoomTopic(c) => convert(RoomTopic, Self::RoomTopic, c), + } } } @@ -130,9 +159,16 @@ where type Raw = StrippedStateContent; type Err = C::Err; - fn try_from_raw(raw: StrippedStateContent) -> Result { + fn try_from_raw(mut raw: StrippedStateContent) -> Result { Ok(Self { - content: C::try_from_raw(raw.content).map_err(|(msg, raw)| (msg, unimplemented!()))?, + content: match C::try_from_raw(raw.content) { + Ok(c) => c, + Err((msg, raw_content)) => { + // we moved raw.content, so we need to put it back before returning raw + raw.content = raw_content; + return Err((msg, raw)); + } + }, event_type: raw.event_type, state_key: raw.state_key, sender: raw.sender, @@ -164,13 +200,58 @@ impl Serialize for StrippedState { impl<'de, C> Deserialize<'de> for StrippedStateContent where - C: Deserialize<'de>, + C: DeserializeOwned, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - unimplemented!() + use serde::de::Error as _; + use serde_json::from_value; + + let conv_err = |error: serde_json::Error| D::Error::custom(error.to_string()); + + // TODO: Optimize + let value = Value::deserialize(deserializer)?; + + let event_type = from_value( + value + .get("type") + .map(Clone::clone) + .ok_or_else(|| D::Error::missing_field("type"))?, + ) + .map_err(conv_err)?; + + let content = from_value( + value + .get("content") + .map(Clone::clone) + .ok_or_else(|| D::Error::missing_field("content"))?, + ) + .map_err(conv_err)?; + + let sender = from_value( + value + .get("sender") + .map(Clone::clone) + .ok_or_else(|| D::Error::missing_field("sender"))?, + ) + .map_err(conv_err)?; + + let state_key = from_value( + value + .get("state_key") + .map(Clone::clone) + .ok_or_else(|| D::Error::missing_field("state_key"))?, + ) + .map_err(conv_err)?; + + Ok(Self { + content, + event_type, + state_key, + sender, + }) } } @@ -270,7 +351,44 @@ mod raw { where D: Deserializer<'de>, { - unimplemented!() + use crate::EventType::*; + use serde::de::Error as _; + use serde_json::{from_value, Value}; + + let conv_err = |error: serde_json::Error| D::Error::custom(error.to_string()); + + // TODO: Optimize + let value = Value::deserialize(deserializer)?; + + let event_type = from_value( + value + .get("type") + .map(Clone::clone) + .ok_or_else(|| D::Error::missing_field("type"))?, + ) + .map_err(conv_err)?; + + Ok(match event_type { + RoomAliases => StrippedState::RoomAliases(from_value(value).map_err(conv_err)?), + RoomAvatar => Self::RoomAvatar(from_value(value).map_err(conv_err)?), + RoomCanonicalAlias => { + Self::RoomCanonicalAlias(from_value(value).map_err(conv_err)?) + } + RoomCreate => Self::RoomCreate(from_value(value).map_err(conv_err)?), + RoomGuestAccess => Self::RoomGuestAccess(from_value(value).map_err(conv_err)?), + RoomHistoryVisibility => { + Self::RoomHistoryVisibility(from_value(value).map_err(conv_err)?) + } + RoomJoinRules => Self::RoomJoinRules(from_value(value).map_err(conv_err)?), + RoomMember => Self::RoomMember(from_value(value).map_err(conv_err)?), + RoomName => Self::RoomName(from_value(value).map_err(conv_err)?), + RoomPowerLevels => Self::RoomPowerLevels(from_value(value).map_err(conv_err)?), + RoomThirdPartyInvite => { + Self::RoomThirdPartyInvite(from_value(value).map_err(conv_err)?) + } + RoomTopic => Self::RoomTopic(from_value(value).map_err(conv_err)?), + _ => return Err(D::Error::custom("not a state event")), + }) } } }