Move event content collection trait impl's into macro code
* Move the EventContent and content marker traits into macro. * Move the raw AnyStateEventContent enum and RawEventContent trait into macro, generate all of the AnyStateEventContent type and impls needed for raw. * Factor out raw mod codegen to seperate fn, add docs to codegen enum + variants, remove unused imports
This commit is contained in:
parent
5091b9a9a8
commit
80ff10ae6a
@ -10,52 +10,169 @@ use parse::RumaCollectionInput;
|
||||
pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream> {
|
||||
let attrs = &input.attrs;
|
||||
let ident = &input.name;
|
||||
let event_type_str = &input.events;
|
||||
|
||||
let variants = input
|
||||
let variants = input.events.iter().map(to_camel_case).collect::<Vec<_>>();
|
||||
let content = input
|
||||
.events
|
||||
.iter()
|
||||
.map(|lit| {
|
||||
let content_docstring = lit;
|
||||
let var = to_camel_case(lit);
|
||||
let content = to_event_content(lit);
|
||||
|
||||
quote! {
|
||||
#[doc = #content_docstring]
|
||||
#var(#content)
|
||||
}
|
||||
})
|
||||
.map(to_event_content_path)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let collection = quote! {
|
||||
#( #attrs )*
|
||||
#[derive(Clone, Debug, /*Serialize*/)]
|
||||
//#[serde(untagged)]
|
||||
#[derive(Clone, Debug, ::serde::Serialize)]
|
||||
#[serde(untagged)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum #ident {
|
||||
#( #variants ),*
|
||||
#(
|
||||
#[doc = #event_type_str]
|
||||
#variants(#content)
|
||||
),*
|
||||
}
|
||||
};
|
||||
|
||||
Ok(collection)
|
||||
let event_content_impl = quote! {
|
||||
impl ::ruma_events::EventContent for #ident {
|
||||
fn event_type(&self) -> &str {
|
||||
match self {
|
||||
#( Self::#variants(content) => content.event_type()),*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let try_from_raw_impl = quote! {
|
||||
impl ::ruma_events::TryFromRaw for #ident {
|
||||
type Raw = raw::#ident;
|
||||
type Err = String;
|
||||
|
||||
fn try_from_raw(raw: Self::Raw) -> Result<Self, Self::Err> {
|
||||
use raw::#ident::*;
|
||||
|
||||
match raw {
|
||||
#( #variants(c) => {
|
||||
let content = ::ruma_events::TryFromRaw::try_from_raw(c)
|
||||
.map_err(|e: <#content as ::ruma_events::TryFromRaw>::Err| e.to_string())?;
|
||||
// without this ^^^^^^^^^^^ the compiler fails to infer the type
|
||||
Ok(Self::#variants(content))
|
||||
}
|
||||
),*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let raw_mod = expand_raw_content_event(&input, &variants)?;
|
||||
|
||||
Ok(quote! {
|
||||
#collection
|
||||
|
||||
#try_from_raw_impl
|
||||
|
||||
#event_content_impl
|
||||
|
||||
impl RoomEventContent for AnyStateEventContent {}
|
||||
|
||||
impl StateEventContent for AnyStateEventContent {}
|
||||
|
||||
#raw_mod
|
||||
})
|
||||
}
|
||||
|
||||
/// Splits the given `event_type` string on `.` and `_` removing the `m.` then
|
||||
/// using only the event name append "EventContent".
|
||||
fn to_event_content(name: &LitStr) -> Ident {
|
||||
fn expand_raw_content_event(
|
||||
input: &RumaCollectionInput,
|
||||
variants: &[Ident],
|
||||
) -> syn::Result<TokenStream> {
|
||||
let ident = &input.name;
|
||||
let event_type_str = &input.events;
|
||||
|
||||
let raw_docs = format!("The raw version of {}, allows for deserialization.", ident);
|
||||
let raw_content = input
|
||||
.events
|
||||
.iter()
|
||||
.map(to_raw_event_content_path)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let raw_collection = quote! {
|
||||
#[doc = #raw_docs]
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum #ident {
|
||||
#(
|
||||
#[doc = #event_type_str]
|
||||
#variants(#raw_content)
|
||||
),*
|
||||
}
|
||||
};
|
||||
|
||||
let raw_event_content_impl = quote! {
|
||||
impl ::ruma_events::RawEventContent for #ident {
|
||||
fn from_parts(event_type: &str, input: Box<::serde_json::value::RawValue>) -> Result<Self, String> {
|
||||
match event_type {
|
||||
#(
|
||||
#event_type_str => {
|
||||
let content = #raw_content::from_parts(event_type, input)?;
|
||||
Ok(#ident::#variants(content))
|
||||
},
|
||||
)*
|
||||
ev => Err(format!("event not supported {}", ev)),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
mod raw {
|
||||
#raw_collection
|
||||
|
||||
#raw_event_content_impl
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn to_event_content_path(
|
||||
name: &LitStr,
|
||||
) -> syn::punctuated::Punctuated<syn::Token![::], syn::PathSegment> {
|
||||
let span = name.span();
|
||||
let name = name.value();
|
||||
|
||||
assert_eq!(&name[..2], "m.");
|
||||
|
||||
let event = name[2..].split('.').last().unwrap();
|
||||
let event_str = name[2..].split('.').last().unwrap();
|
||||
|
||||
let event = event
|
||||
let event = event_str
|
||||
.split('_')
|
||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||
.collect::<String>();
|
||||
|
||||
let content_str = format!("{}EventContent", event);
|
||||
Ident::new(&content_str, span)
|
||||
let module = Ident::new(event_str, span);
|
||||
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
||||
syn::parse_quote! {
|
||||
::ruma_events::room::#module::#content_str
|
||||
}
|
||||
}
|
||||
|
||||
fn to_raw_event_content_path(
|
||||
name: &LitStr,
|
||||
) -> syn::punctuated::Punctuated<syn::Token![::], syn::PathSegment> {
|
||||
let span = name.span();
|
||||
let name = name.value();
|
||||
|
||||
assert_eq!(&name[..2], "m.");
|
||||
|
||||
let event_str = name[2..].split('.').last().unwrap();
|
||||
|
||||
let event = event_str
|
||||
.split('_')
|
||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||
.collect::<String>();
|
||||
|
||||
let module = Ident::new(event_str, span);
|
||||
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
||||
syn::parse_quote! {
|
||||
::ruma_events::room::#module::raw::#content_str
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits the given `event_type` string on `.` and `_` removing the `m.room.` then
|
||||
|
@ -14,7 +14,6 @@
|
||||
clippy::items_after_statements,
|
||||
clippy::match_same_arms,
|
||||
clippy::mem_forget,
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::multiple_inherent_impl,
|
||||
clippy::mut_mut,
|
||||
clippy::needless_borrow,
|
||||
|
@ -3,12 +3,6 @@
|
||||
use ruma_events_macros::{FromRaw, StateEventContent};
|
||||
use ruma_identifiers::RoomAliasId;
|
||||
use serde::Serialize;
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
error::{InvalidEvent, InvalidEventKind},
|
||||
EventContent, EventJson, RoomEventContent, StateEventContent,
|
||||
};
|
||||
|
||||
/// Informs the room about what room aliases it has been given.
|
||||
#[derive(Clone, Debug, Serialize, FromRaw, StateEventContent)]
|
||||
|
@ -2,13 +2,8 @@
|
||||
|
||||
use ruma_events_macros::{FromRaw, StateEventContent};
|
||||
use serde::Serialize;
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use super::ImageInfo;
|
||||
use crate::{
|
||||
error::{InvalidEvent, InvalidEventKind},
|
||||
EventContent, EventJson, RoomEventContent, StateEventContent,
|
||||
};
|
||||
|
||||
/// A picture that is associated with the room.
|
||||
///
|
||||
|
105
src/state.rs
105
src/state.rs
@ -3,26 +3,17 @@
|
||||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde::{
|
||||
de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor},
|
||||
ser::{Error, SerializeStruct},
|
||||
Serialize, Serializer,
|
||||
};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
error::{InvalidEvent, InvalidEventKind},
|
||||
room::{aliases::AliasesEventContent, avatar::AvatarEventContent},
|
||||
EventContent, FromRaw, RawEventContent, RoomEventContent, StateEventContent, TryFromRaw,
|
||||
UnsignedData,
|
||||
};
|
||||
use crate::{RawEventContent, RoomEventContent, StateEventContent, TryFromRaw, UnsignedData};
|
||||
use ruma_events_macros::event_content_collection;
|
||||
|
||||
event_content_collection! {
|
||||
@ -65,50 +56,12 @@ where
|
||||
pub unsigned: UnsignedData,
|
||||
}
|
||||
|
||||
impl FromRaw for AnyStateEventContent {
|
||||
type Raw = raw::AnyStateEventContent;
|
||||
|
||||
fn from_raw(raw: Self::Raw) -> Self {
|
||||
use raw::AnyStateEventContent::*;
|
||||
|
||||
match raw {
|
||||
RoomAliases(c) => Self::RoomAliases(FromRaw::from_raw(c)),
|
||||
RoomAvatar(c) => Self::RoomAvatar(FromRaw::from_raw(c)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for AnyStateEventContent {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
AnyStateEventContent::RoomAliases(content) => content.serialize(serializer),
|
||||
AnyStateEventContent::RoomAvatar(content) => content.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventContent for AnyStateEventContent {
|
||||
fn event_type(&self) -> &str {
|
||||
match self {
|
||||
AnyStateEventContent::RoomAliases(content) => content.event_type(),
|
||||
AnyStateEventContent::RoomAvatar(content) => content.event_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RoomEventContent for AnyStateEventContent {}
|
||||
|
||||
impl StateEventContent for AnyStateEventContent {}
|
||||
|
||||
impl<C> TryFromRaw for StateEvent<C>
|
||||
where
|
||||
C: StateEventContent + TryFromRaw,
|
||||
C::Raw: RawEventContent,
|
||||
{
|
||||
type Raw = raw::StateEvent<C::Raw>;
|
||||
type Raw = raw_state_event::StateEvent<C::Raw>;
|
||||
type Err = C::Err;
|
||||
|
||||
fn try_from_raw(raw: Self::Raw) -> Result<Self, Self::Err> {
|
||||
@ -156,7 +109,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
mod raw {
|
||||
mod raw_state_event {
|
||||
use std::{
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
@ -164,51 +117,11 @@ mod raw {
|
||||
};
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_events_macros::event_content_collection;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde::{
|
||||
de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor},
|
||||
Serialize,
|
||||
};
|
||||
use serde::de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
room::{aliases::raw::AliasesEventContent, avatar::raw::AvatarEventContent},
|
||||
RawEventContent, UnsignedData,
|
||||
};
|
||||
|
||||
event_content_collection! {
|
||||
/// A state event.
|
||||
name: AnyStateEventContent,
|
||||
events: ["m.room.aliases", "m.room.avatar"]
|
||||
}
|
||||
|
||||
impl RawEventContent for AnyStateEventContent {
|
||||
fn from_parts(event_type: &str, content: Box<RawJsonValue>) -> Result<Self, String> {
|
||||
fn deserialize_variant<T: RawEventContent>(
|
||||
ev_type: &str,
|
||||
input: Box<RawJsonValue>,
|
||||
variant: fn(T) -> AnyStateEventContent,
|
||||
) -> Result<AnyStateEventContent, String> {
|
||||
let content = T::from_parts(ev_type, input)?;
|
||||
Ok(variant(content))
|
||||
}
|
||||
|
||||
match event_type {
|
||||
"m.room.avatar" => deserialize_variant::<AvatarEventContent>(
|
||||
event_type,
|
||||
content,
|
||||
AnyStateEventContent::RoomAvatar,
|
||||
),
|
||||
"m.room.aliases" => deserialize_variant::<AliasesEventContent>(
|
||||
event_type,
|
||||
content,
|
||||
AnyStateEventContent::RoomAliases,
|
||||
),
|
||||
ev => Err(format!("event not supported {}", ev)),
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::{RawEventContent, UnsignedData};
|
||||
|
||||
/// State event.
|
||||
#[derive(Clone, Debug)]
|
||||
@ -403,9 +316,11 @@ mod tests {
|
||||
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
|
||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||
|
||||
use super::{AliasesEventContent, AnyStateEventContent, AvatarEventContent, StateEvent};
|
||||
use super::{AnyStateEventContent, StateEvent};
|
||||
use crate::{
|
||||
room::{ImageInfo, ThumbnailInfo},
|
||||
room::{
|
||||
aliases::AliasesEventContent, avatar::AvatarEventContent, ImageInfo, ThumbnailInfo,
|
||||
},
|
||||
EventJson, UnsignedData,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user