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> {
|
pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream> {
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
let ident = &input.name;
|
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
|
.events
|
||||||
.iter()
|
.iter()
|
||||||
.map(|lit| {
|
.map(to_event_content_path)
|
||||||
let content_docstring = lit;
|
|
||||||
let var = to_camel_case(lit);
|
|
||||||
let content = to_event_content(lit);
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#[doc = #content_docstring]
|
|
||||||
#var(#content)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let collection = quote! {
|
let collection = quote! {
|
||||||
#( #attrs )*
|
#( #attrs )*
|
||||||
#[derive(Clone, Debug, /*Serialize*/)]
|
#[derive(Clone, Debug, ::serde::Serialize)]
|
||||||
//#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum #ident {
|
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
|
fn expand_raw_content_event(
|
||||||
/// using only the event name append "EventContent".
|
input: &RumaCollectionInput,
|
||||||
fn to_event_content(name: &LitStr) -> Ident {
|
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 span = name.span();
|
||||||
let name = name.value();
|
let name = name.value();
|
||||||
|
|
||||||
assert_eq!(&name[..2], "m.");
|
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('_')
|
.split('_')
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
let content_str = format!("{}EventContent", event);
|
let module = Ident::new(event_str, span);
|
||||||
Ident::new(&content_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
|
/// Splits the given `event_type` string on `.` and `_` removing the `m.room.` then
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
clippy::items_after_statements,
|
clippy::items_after_statements,
|
||||||
clippy::match_same_arms,
|
clippy::match_same_arms,
|
||||||
clippy::mem_forget,
|
clippy::mem_forget,
|
||||||
clippy::missing_docs_in_private_items,
|
|
||||||
clippy::multiple_inherent_impl,
|
clippy::multiple_inherent_impl,
|
||||||
clippy::mut_mut,
|
clippy::mut_mut,
|
||||||
clippy::needless_borrow,
|
clippy::needless_borrow,
|
||||||
|
@ -3,12 +3,6 @@
|
|||||||
use ruma_events_macros::{FromRaw, StateEventContent};
|
use ruma_events_macros::{FromRaw, StateEventContent};
|
||||||
use ruma_identifiers::RoomAliasId;
|
use ruma_identifiers::RoomAliasId;
|
||||||
use serde::Serialize;
|
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.
|
/// Informs the room about what room aliases it has been given.
|
||||||
#[derive(Clone, Debug, Serialize, FromRaw, StateEventContent)]
|
#[derive(Clone, Debug, Serialize, FromRaw, StateEventContent)]
|
||||||
|
@ -2,13 +2,8 @@
|
|||||||
|
|
||||||
use ruma_events_macros::{FromRaw, StateEventContent};
|
use ruma_events_macros::{FromRaw, StateEventContent};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
|
||||||
|
|
||||||
use super::ImageInfo;
|
use super::ImageInfo;
|
||||||
use crate::{
|
|
||||||
error::{InvalidEvent, InvalidEventKind},
|
|
||||||
EventContent, EventJson, RoomEventContent, StateEventContent,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A picture that is associated with the room.
|
/// A picture that is associated with the room.
|
||||||
///
|
///
|
||||||
|
105
src/state.rs
105
src/state.rs
@ -3,26 +3,17 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
fmt,
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
marker::PhantomData,
|
|
||||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor},
|
|
||||||
ser::{Error, SerializeStruct},
|
ser::{Error, SerializeStruct},
|
||||||
Serialize, Serializer,
|
Serialize, Serializer,
|
||||||
};
|
};
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{RawEventContent, RoomEventContent, StateEventContent, TryFromRaw, UnsignedData};
|
||||||
error::{InvalidEvent, InvalidEventKind},
|
|
||||||
room::{aliases::AliasesEventContent, avatar::AvatarEventContent},
|
|
||||||
EventContent, FromRaw, RawEventContent, RoomEventContent, StateEventContent, TryFromRaw,
|
|
||||||
UnsignedData,
|
|
||||||
};
|
|
||||||
use ruma_events_macros::event_content_collection;
|
use ruma_events_macros::event_content_collection;
|
||||||
|
|
||||||
event_content_collection! {
|
event_content_collection! {
|
||||||
@ -65,50 +56,12 @@ where
|
|||||||
pub unsigned: UnsignedData,
|
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>
|
impl<C> TryFromRaw for StateEvent<C>
|
||||||
where
|
where
|
||||||
C: StateEventContent + TryFromRaw,
|
C: StateEventContent + TryFromRaw,
|
||||||
C::Raw: RawEventContent,
|
C::Raw: RawEventContent,
|
||||||
{
|
{
|
||||||
type Raw = raw::StateEvent<C::Raw>;
|
type Raw = raw_state_event::StateEvent<C::Raw>;
|
||||||
type Err = C::Err;
|
type Err = C::Err;
|
||||||
|
|
||||||
fn try_from_raw(raw: Self::Raw) -> Result<Self, Self::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::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@ -164,51 +117,11 @@ mod raw {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_events_macros::event_content_collection;
|
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde::{
|
use serde::de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor};
|
||||||
de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor},
|
|
||||||
Serialize,
|
|
||||||
};
|
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
use crate::{
|
use crate::{RawEventContent, UnsignedData};
|
||||||
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)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// State event.
|
/// State event.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -403,9 +316,11 @@ mod tests {
|
|||||||
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
|
||||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
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::{
|
use crate::{
|
||||||
room::{ImageInfo, ThumbnailInfo},
|
room::{
|
||||||
|
aliases::AliasesEventContent, avatar::AvatarEventContent, ImageInfo, ThumbnailInfo,
|
||||||
|
},
|
||||||
EventJson, UnsignedData,
|
EventJson, UnsignedData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user