Remove event_enum! and only use event_content_enum
This commit is contained in:
parent
92a2dfa2e8
commit
2a91dc1eb7
@ -2,29 +2,10 @@
|
|||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{Ident, LitStr};
|
use syn::{
|
||||||
|
parse::{self, Parse, ParseStream},
|
||||||
use parse::ContentEnumInput;
|
Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token,
|
||||||
|
};
|
||||||
fn marker_traits(ident: &Ident) -> TokenStream {
|
|
||||||
match ident.to_string().as_str() {
|
|
||||||
"AnyStateEventContent" => quote! {
|
|
||||||
impl ::ruma_events::RoomEventContent for #ident {}
|
|
||||||
impl ::ruma_events::StateEventContent for #ident {}
|
|
||||||
},
|
|
||||||
"AnyMessageEventContent" => quote! {
|
|
||||||
impl ::ruma_events::RoomEventContent for #ident {}
|
|
||||||
impl ::ruma_events::MessageEventContent for #ident {}
|
|
||||||
},
|
|
||||||
"AnyEphemeralRoomEventContent" => quote! {
|
|
||||||
impl ::ruma_events::EphemeralRoomEventContent for #ident {}
|
|
||||||
},
|
|
||||||
"AnyBasicEventContent" => quote! {
|
|
||||||
impl ::ruma_events::BasicEventContent for #ident {}
|
|
||||||
},
|
|
||||||
_ => TokenStream::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a content enum from `ContentEnumInput`.
|
/// Create a content enum from `ContentEnumInput`.
|
||||||
pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream> {
|
pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream> {
|
||||||
@ -85,6 +66,26 @@ pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn marker_traits(ident: &Ident) -> TokenStream {
|
||||||
|
match ident.to_string().as_str() {
|
||||||
|
"AnyStateEventContent" => quote! {
|
||||||
|
impl ::ruma_events::RoomEventContent for #ident {}
|
||||||
|
impl ::ruma_events::StateEventContent for #ident {}
|
||||||
|
},
|
||||||
|
"AnyMessageEventContent" => quote! {
|
||||||
|
impl ::ruma_events::RoomEventContent for #ident {}
|
||||||
|
impl ::ruma_events::MessageEventContent for #ident {}
|
||||||
|
},
|
||||||
|
"AnyEphemeralRoomEventContent" => quote! {
|
||||||
|
impl ::ruma_events::EphemeralRoomEventContent for #ident {}
|
||||||
|
},
|
||||||
|
"AnyBasicEventContent" => quote! {
|
||||||
|
impl ::ruma_events::BasicEventContent for #ident {}
|
||||||
|
},
|
||||||
|
_ => TokenStream::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_event_content_path(
|
fn to_event_content_path(
|
||||||
name: &LitStr,
|
name: &LitStr,
|
||||||
) -> syn::punctuated::Punctuated<syn::Token![::], syn::PathSegment> {
|
) -> syn::punctuated::Punctuated<syn::Token![::], syn::PathSegment> {
|
||||||
@ -113,7 +114,14 @@ fn to_event_content_path(
|
|||||||
pub(crate) fn to_camel_case(name: &LitStr) -> Ident {
|
pub(crate) fn to_camel_case(name: &LitStr) -> Ident {
|
||||||
let span = name.span();
|
let span = name.span();
|
||||||
let name = name.value();
|
let name = name.value();
|
||||||
assert_eq!(&name[..2], "m.");
|
|
||||||
|
if &name[..2] != "m." {
|
||||||
|
panic!(
|
||||||
|
"well-known matrix events have to start with `m.` found `{}`",
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let s = name[2..]
|
let s = name[2..]
|
||||||
.split(&['.', '_'] as &[char])
|
.split(&['.', '_'] as &[char])
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||||
@ -121,21 +129,14 @@ pub(crate) fn to_camel_case(name: &LitStr) -> Ident {
|
|||||||
Ident::new(&s, span)
|
Ident::new(&s, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Details of parsing input for the `event_content_content_enum` procedural macro.
|
/// Custom keywords for the `event_content_content_enum!` macro
|
||||||
pub mod parse {
|
mod kw {
|
||||||
use syn::{
|
|
||||||
parse::{self, Parse, ParseStream},
|
|
||||||
Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Custom keywords for the `event_content_content_enum!` macro
|
|
||||||
mod kw {
|
|
||||||
syn::custom_keyword!(name);
|
syn::custom_keyword!(name);
|
||||||
syn::custom_keyword!(events);
|
syn::custom_keyword!(events);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entire `event_content_content_enum!` macro structure directly as it appears in the source code..
|
/// The entire `event_content_content_enum!` macro structure directly as it appears in the source code..
|
||||||
pub struct ContentEnumInput {
|
pub struct ContentEnumInput {
|
||||||
/// Outer attributes on the field, such as a docstring.
|
/// Outer attributes on the field, such as a docstring.
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
|
|
||||||
@ -147,9 +148,9 @@ pub mod parse {
|
|||||||
/// this event (converted to a valid Rust-style type name by stripping `m.`, replacing the
|
/// this event (converted to a valid Rust-style type name by stripping `m.`, replacing the
|
||||||
/// remaining dots by underscores and then converting from snake_case to CamelCase).
|
/// remaining dots by underscores and then converting from snake_case to CamelCase).
|
||||||
pub events: Vec<LitStr>,
|
pub events: Vec<LitStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for ContentEnumInput {
|
impl Parse for ContentEnumInput {
|
||||||
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||||
let attrs = input.call(Attribute::parse_outer)?;
|
let attrs = input.call(Attribute::parse_outer)?;
|
||||||
// name field
|
// name field
|
||||||
@ -188,5 +189,4 @@ pub mod parse {
|
|||||||
events,
|
events,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,14 @@ fn expand_deserialize_event(
|
|||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
) -> syn::Result<TokenStream> {
|
) -> syn::Result<TokenStream> {
|
||||||
let ident = &input.ident;
|
let ident = &input.ident;
|
||||||
let content_ident = Ident::new(&format!("{}Content", ident), input.ident.span());
|
// we know there is a content field already
|
||||||
|
let content_type = fields
|
||||||
|
.iter()
|
||||||
|
// we also know that the fields are named and have an ident
|
||||||
|
.find(|f| f.ident.as_ref().unwrap() == "content")
|
||||||
|
.map(|f| f.ty.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let (impl_generics, ty_gen, where_clause) = input.generics.split_for_impl();
|
let (impl_generics, ty_gen, where_clause) = input.generics.split_for_impl();
|
||||||
|
|
||||||
let enum_variants = fields
|
let enum_variants = fields
|
||||||
@ -121,7 +128,7 @@ fn expand_deserialize_event(
|
|||||||
if is_generic {
|
if is_generic {
|
||||||
quote! { Box<::serde_json::value::RawValue> }
|
quote! { Box<::serde_json::value::RawValue> }
|
||||||
} else {
|
} else {
|
||||||
quote! { #content_ident }
|
quote! { #content_type }
|
||||||
}
|
}
|
||||||
} else if name == "origin_server_ts" {
|
} else if name == "origin_server_ts" {
|
||||||
quote! { ::js_int::UInt }
|
quote! { ::js_int::UInt }
|
||||||
@ -221,7 +228,7 @@ fn expand_deserialize_event(
|
|||||||
type Value = #ident #ty_gen;
|
type Value = #ident #ty_gen;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn expecting(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
write!(formatter, "struct implementing {}", stringify!(#content_ident))
|
write!(formatter, "struct implementing {}", stringify!(#content_type))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
@ -1,270 +0,0 @@
|
|||||||
//! Implementation of event enum and event content enum macros.
|
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
|
||||||
use quote::quote;
|
|
||||||
use syn::{
|
|
||||||
parse::{self, Parse, ParseStream},
|
|
||||||
Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Create a content enum from `EventEnumInput`.
|
|
||||||
pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
|
|
||||||
let attrs = &input.attrs;
|
|
||||||
let ident = &input.name;
|
|
||||||
let event_type_str = &input.events;
|
|
||||||
|
|
||||||
let variants = input.events.iter().map(to_camel_case).collect::<Vec<_>>();
|
|
||||||
let content = input.events.iter().map(to_event_path).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let event_enum = quote! {
|
|
||||||
#( #attrs )*
|
|
||||||
#[derive(Clone, Debug, ::serde::Serialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
pub enum #ident {
|
|
||||||
#(
|
|
||||||
#[doc = #event_type_str]
|
|
||||||
#variants(#content)
|
|
||||||
),*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let event_deserialize_impl = quote! {
|
|
||||||
impl<'de> ::serde::de::Deserialize<'de> for #ident {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: ::serde::de::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
use ::serde::de::Error as _;
|
|
||||||
|
|
||||||
let json = ::serde_json::Value::deserialize(deserializer)?;
|
|
||||||
let ev_type: String = ::ruma_events::util::get_field(&json, "type")?;
|
|
||||||
match ev_type.as_str() {
|
|
||||||
#(
|
|
||||||
#event_type_str => {
|
|
||||||
let event = ::serde_json::from_value::<#content>(json).map_err(D::Error::custom)?;
|
|
||||||
Ok(#ident::#variants(event))
|
|
||||||
},
|
|
||||||
)*
|
|
||||||
_ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let event_content_enum = expand_content_enum(input)?;
|
|
||||||
|
|
||||||
Ok(quote! {
|
|
||||||
#event_enum
|
|
||||||
|
|
||||||
#event_deserialize_impl
|
|
||||||
|
|
||||||
#event_content_enum
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a content enum from `EventEnumInput`.
|
|
||||||
pub fn expand_content_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
|
|
||||||
let attrs = &input.attrs;
|
|
||||||
let ident = Ident::new(
|
|
||||||
&format!("{}Content", input.name.to_string()),
|
|
||||||
input.name.span(),
|
|
||||||
);
|
|
||||||
let event_type_str = &input.events;
|
|
||||||
|
|
||||||
let variants = input.events.iter().map(to_camel_case).collect::<Vec<_>>();
|
|
||||||
let content = input
|
|
||||||
.events
|
|
||||||
.iter()
|
|
||||||
.map(to_event_content_path)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let content_enum = quote! {
|
|
||||||
#( #attrs )*
|
|
||||||
#[derive(Clone, Debug, ::serde::Serialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
pub enum #ident {
|
|
||||||
#(
|
|
||||||
#[doc = #event_type_str]
|
|
||||||
#variants(#content)
|
|
||||||
),*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let event_content_impl = quote! {
|
|
||||||
impl ::ruma_events::EventContent for #ident {
|
|
||||||
fn event_type(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
#( Self::#variants(content) => content.event_type() ),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_parts(event_type: &str, input: Box<::serde_json::value::RawValue>) -> Result<Self, String> {
|
|
||||||
match event_type {
|
|
||||||
#(
|
|
||||||
#event_type_str => {
|
|
||||||
let content = #content::from_parts(event_type, input)?;
|
|
||||||
Ok(#ident::#variants(content))
|
|
||||||
},
|
|
||||||
)*
|
|
||||||
ev => Err(format!("event not supported {}", ev)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let marker_trait_impls = marker_traits(&ident);
|
|
||||||
|
|
||||||
Ok(quote! {
|
|
||||||
#content_enum
|
|
||||||
|
|
||||||
#event_content_impl
|
|
||||||
|
|
||||||
#marker_trait_impls
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marker_traits(ident: &Ident) -> TokenStream {
|
|
||||||
match ident.to_string().as_str() {
|
|
||||||
"AnyStateEventContent" => quote! {
|
|
||||||
impl ::ruma_events::RoomEventContent for #ident {}
|
|
||||||
impl ::ruma_events::StateEventContent for #ident {}
|
|
||||||
},
|
|
||||||
"AnyMessageEventContent" => quote! {
|
|
||||||
impl ::ruma_events::RoomEventContent for #ident {}
|
|
||||||
impl ::ruma_events::MessageEventContent for #ident {}
|
|
||||||
},
|
|
||||||
"AnyEphemeralRoomEventContent" => quote! {
|
|
||||||
impl ::ruma_events::EphemeralRoomEventContent for #ident {}
|
|
||||||
},
|
|
||||||
"AnyBasicEventContent" => quote! {
|
|
||||||
impl ::ruma_events::BasicEventContent for #ident {}
|
|
||||||
},
|
|
||||||
_ => TokenStream::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_event_path(name: &LitStr) -> TokenStream {
|
|
||||||
let span = name.span();
|
|
||||||
let name = name.value();
|
|
||||||
|
|
||||||
assert_eq!(&name[..2], "m.");
|
|
||||||
|
|
||||||
let path = name[2..].split('.').collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let event_str = path.last().unwrap();
|
|
||||||
let event = event_str
|
|
||||||
.split('_')
|
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let content_str = Ident::new(&format!("{}Event", event), span);
|
|
||||||
let path = path.iter().map(|s| Ident::new(s, span));
|
|
||||||
quote! {
|
|
||||||
::ruma_events::#( #path )::*::#content_str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_event_content_path(name: &LitStr) -> TokenStream {
|
|
||||||
let span = name.span();
|
|
||||||
let name = name.value();
|
|
||||||
|
|
||||||
assert_eq!(&name[..2], "m.");
|
|
||||||
|
|
||||||
let path = name[2..].split('.').collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let event_str = path.last().unwrap();
|
|
||||||
let event = event_str
|
|
||||||
.split('_')
|
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
|
||||||
let path = path.iter().map(|s| Ident::new(s, span));
|
|
||||||
quote! {
|
|
||||||
::ruma_events::#( #path )::*::#content_str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Splits the given `event_type` string on `.` and `_` removing the `m.room.` then
|
|
||||||
/// camel casing to give the `Event` struct name.
|
|
||||||
pub(crate) fn to_camel_case(name: &LitStr) -> Ident {
|
|
||||||
let span = name.span();
|
|
||||||
let name = name.value();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
&name[..2],
|
|
||||||
"m.",
|
|
||||||
"well-known matrix events have to start with `m.`"
|
|
||||||
);
|
|
||||||
|
|
||||||
let s = name[2..]
|
|
||||||
.split(&['.', '_'] as &[char])
|
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
Ident::new(&s, span)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Custom keywords for the `event_enum!` macro
|
|
||||||
mod kw {
|
|
||||||
syn::custom_keyword!(name);
|
|
||||||
syn::custom_keyword!(events);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The entire `event_enum!` macro structure directly as it appears in the source code.
|
|
||||||
pub struct EventEnumInput {
|
|
||||||
/// Outer attributes on the field, such as a docstring.
|
|
||||||
pub attrs: Vec<Attribute>,
|
|
||||||
|
|
||||||
/// The name of the event.
|
|
||||||
pub name: Ident,
|
|
||||||
|
|
||||||
/// An array of valid matrix event types. This will generate the variants of the event type "name".
|
|
||||||
/// There needs to be a corresponding variant in `ruma_events::EventType` for
|
|
||||||
/// this event (converted to a valid Rust-style type name by stripping `m.`, replacing the
|
|
||||||
/// remaining dots by underscores and then converting from snake_case to CamelCase).
|
|
||||||
pub events: Vec<LitStr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for EventEnumInput {
|
|
||||||
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
|
||||||
let attrs = input.call(Attribute::parse_outer)?;
|
|
||||||
// name field
|
|
||||||
input.parse::<kw::name>()?;
|
|
||||||
input.parse::<Token![:]>()?;
|
|
||||||
// the name of our event enum
|
|
||||||
let name: Ident = input.parse()?;
|
|
||||||
input.parse::<Token![,]>()?;
|
|
||||||
|
|
||||||
// events field
|
|
||||||
input.parse::<kw::events>()?;
|
|
||||||
input.parse::<Token![:]>()?;
|
|
||||||
|
|
||||||
// an array of event names `["m.room.whatever"]`
|
|
||||||
let ev_array = input.parse::<syn::ExprArray>()?;
|
|
||||||
let events = ev_array
|
|
||||||
.elems
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| {
|
|
||||||
if let Expr::Lit(ExprLit {
|
|
||||||
lit: Lit::Str(lit_str),
|
|
||||||
..
|
|
||||||
}) = item
|
|
||||||
{
|
|
||||||
Ok(lit_str)
|
|
||||||
} else {
|
|
||||||
let msg = "values of field `events` are required to be a string literal";
|
|
||||||
Err(syn::Error::new_spanned(item, msg))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<syn::Result<_>>()?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
attrs,
|
|
||||||
name,
|
|
||||||
events,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
//! Crate `ruma_events_macros` provides a procedural macro for generating
|
//! Crate `ruma_events_macros` provides a procedural macro for generating
|
||||||
//! [ruma-events](https://github.com/ruma/ruma-events) events.
|
//! [ruma-events](https://github.com/ruma/ruma-events) events.
|
||||||
//!
|
//!
|
||||||
//! See the documentation for the invidiual macros for usage details.
|
//! See the documentation for the individual macros for usage details.
|
||||||
#![deny(
|
#![deny(
|
||||||
missing_copy_implementations,
|
missing_copy_implementations,
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
@ -14,38 +14,22 @@ use proc_macro::TokenStream;
|
|||||||
use syn::{parse_macro_input, DeriveInput};
|
use syn::{parse_macro_input, DeriveInput};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
content_enum::{expand_content_enum, parse::ContentEnumInput},
|
content_enum::{expand_content_enum, ContentEnumInput},
|
||||||
event::expand_event,
|
event::expand_event,
|
||||||
event_content::{
|
event_content::{
|
||||||
expand_basic_event_content, expand_ephemeral_room_event_content, expand_event_content,
|
expand_basic_event_content, expand_ephemeral_room_event_content, expand_event_content,
|
||||||
expand_message_event_content, expand_room_event_content, expand_state_event_content,
|
expand_message_event_content, expand_room_event_content, expand_state_event_content,
|
||||||
},
|
},
|
||||||
event_enum::{expand_event_enum, EventEnumInput},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod content_enum;
|
mod content_enum;
|
||||||
mod event;
|
mod event;
|
||||||
mod event_content;
|
mod event_content;
|
||||||
mod event_enum;
|
|
||||||
|
|
||||||
/// Generates an enum to represent the various Matrix event types.
|
|
||||||
///
|
|
||||||
/// This macro also implements the necessary traits for the type to serialize and deserialize
|
|
||||||
/// itself.
|
|
||||||
// TODO more docs/example
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn event_enum(input: TokenStream) -> TokenStream {
|
|
||||||
let event_enum_input = syn::parse_macro_input!(input as EventEnumInput);
|
|
||||||
expand_event_enum(event_enum_input)
|
|
||||||
.unwrap_or_else(|err| err.to_compile_error())
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates a content enum to represent the various Matrix event types.
|
/// Generates a content enum to represent the various Matrix event types.
|
||||||
///
|
///
|
||||||
/// This macro also implements the necessary traits for the type to serialize and deserialize
|
/// This macro also implements the necessary traits for the type to serialize and deserialize
|
||||||
/// itself.
|
/// itself.
|
||||||
// TODO more docs/example
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn event_content_enum(input: TokenStream) -> TokenStream {
|
pub fn event_content_enum(input: TokenStream) -> TokenStream {
|
||||||
let content_enum_input = syn::parse_macro_input!(input as ContentEnumInput);
|
let content_enum_input = syn::parse_macro_input!(input as ContentEnumInput);
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
use crate::{EventType, UnsignedData};
|
use crate::UnsignedData;
|
||||||
|
|
||||||
// TODO: (De)serialization
|
// TODO: (De)serialization
|
||||||
|
|
||||||
|
22
src/enums.rs
22
src/enums.rs
@ -1,8 +1,8 @@
|
|||||||
use ruma_events_macros::event_enum;
|
use ruma_events_macros::event_content_enum;
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
/// Any basic event.
|
/// Any basic event.
|
||||||
name: AnyBasicEvent,
|
name: AnyBasicEventContent,
|
||||||
events: [
|
events: [
|
||||||
"m.direct",
|
"m.direct",
|
||||||
"m.dummy",
|
"m.dummy",
|
||||||
@ -13,9 +13,9 @@ event_enum! {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
/// Any ephemeral room event.
|
/// Any ephemeral room event.
|
||||||
name: AnyEphemeralRoomEvent,
|
name: AnyEphemeralRoomEventContent,
|
||||||
events: [
|
events: [
|
||||||
"m.fully_read",
|
"m.fully_read",
|
||||||
"m.receipt",
|
"m.receipt",
|
||||||
@ -23,9 +23,9 @@ event_enum! {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
/// Any message event.
|
/// Any message event.
|
||||||
name: AnyMessageEvent,
|
name: AnyMessageEventContent,
|
||||||
events: [
|
events: [
|
||||||
"m.call.answer",
|
"m.call.answer",
|
||||||
"m.call.invite",
|
"m.call.invite",
|
||||||
@ -37,9 +37,9 @@ event_enum! {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
/// Any state event.
|
/// Any state event.
|
||||||
name: AnyStateEvent,
|
name: AnyStateEventContent,
|
||||||
events: [
|
events: [
|
||||||
"m.room.aliases",
|
"m.room.aliases",
|
||||||
"m.room.avatar",
|
"m.room.avatar",
|
||||||
@ -61,9 +61,9 @@ event_enum! {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
/// Any to-device event.
|
/// Any to-device event.
|
||||||
name: AnyToDeviceEvent,
|
name: AnyToDeviceEventContent,
|
||||||
events: [
|
events: [
|
||||||
"m.dummy",
|
"m.dummy",
|
||||||
"m.room_key",
|
"m.room_key",
|
||||||
|
@ -113,8 +113,6 @@
|
|||||||
#![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)]
|
#![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)]
|
||||||
// Since we support Rust 1.36.0, we can't apply this suggestion yet
|
// Since we support Rust 1.36.0, we can't apply this suggestion yet
|
||||||
#![allow(clippy::use_self)]
|
#![allow(clippy::use_self)]
|
||||||
#![allow(dead_code)]
|
|
||||||
#![allow(unused_imports)]
|
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@ -162,9 +160,8 @@ pub use self::{
|
|||||||
algorithm::Algorithm,
|
algorithm::Algorithm,
|
||||||
custom::{CustomBasicEvent, CustomMessageEvent, CustomStateEvent},
|
custom::{CustomBasicEvent, CustomMessageEvent, CustomStateEvent},
|
||||||
enums::{
|
enums::{
|
||||||
AnyBasicEvent, AnyBasicEventContent, AnyEphemeralRoomEvent, AnyEphemeralRoomEventContent,
|
AnyBasicEventContent, AnyEphemeralRoomEventContent, AnyMessageEventContent,
|
||||||
AnyMessageEvent, AnyMessageEventContent, AnyStateEvent, AnyStateEventContent,
|
AnyStateEventContent, AnyToDeviceEventContent,
|
||||||
AnyToDeviceEvent, AnyToDeviceEventContent,
|
|
||||||
},
|
},
|
||||||
error::{FromStrError, InvalidEvent, InvalidInput},
|
error::{FromStrError, InvalidEvent, InvalidInput},
|
||||||
event_kinds::{
|
event_kinds::{
|
||||||
|
6
tests/event_content_enum.rs
Normal file
6
tests/event_content_enum.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#[test]
|
||||||
|
fn ui() {
|
||||||
|
let t = trybuild::TestCases::new();
|
||||||
|
t.pass("tests/ui/07-enum-sanity-check.rs");
|
||||||
|
t.compile_fail("tests/ui/08-enum-invalid-path.rs");
|
||||||
|
}
|
@ -1,124 +0,0 @@
|
|||||||
use std::{
|
|
||||||
convert::TryFrom,
|
|
||||||
time::{Duration, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
use js_int::UInt;
|
|
||||||
use matches::assert_matches;
|
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
|
||||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
|
||||||
|
|
||||||
use ruma_events::{
|
|
||||||
call::{answer::AnswerEventContent, SessionDescription, SessionDescriptionType},
|
|
||||||
room::{ImageInfo, ThumbnailInfo},
|
|
||||||
sticker::StickerEventContent,
|
|
||||||
AnyMessageEvent, MessageEvent, UnsignedData,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ui() {
|
|
||||||
let t = trybuild::TestCases::new();
|
|
||||||
t.pass("tests/ui/07-enum-sanity-check.rs");
|
|
||||||
t.compile_fail("tests/ui/08-enum-invalid-path.rs");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_message_event() {
|
|
||||||
let json_data = json!({
|
|
||||||
"content": {
|
|
||||||
"answer": {
|
|
||||||
"type": "answer",
|
|
||||||
"sdp": "Hello"
|
|
||||||
},
|
|
||||||
"call_id": "foofoo",
|
|
||||||
"version": 1
|
|
||||||
},
|
|
||||||
"event_id": "$h29iv0s8:example.com",
|
|
||||||
"origin_server_ts": 1,
|
|
||||||
"room_id": "!roomid:room.com",
|
|
||||||
"sender": "@carl:example.com",
|
|
||||||
"type": "m.call.answer"
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_matches!(
|
|
||||||
from_json_value::<AnyMessageEvent>(json_data)
|
|
||||||
.unwrap(),
|
|
||||||
AnyMessageEvent::CallAnswer(MessageEvent {
|
|
||||||
content: AnswerEventContent {
|
|
||||||
answer: SessionDescription {
|
|
||||||
session_type: SessionDescriptionType::Answer,
|
|
||||||
sdp,
|
|
||||||
},
|
|
||||||
call_id,
|
|
||||||
version,
|
|
||||||
},
|
|
||||||
event_id,
|
|
||||||
origin_server_ts,
|
|
||||||
room_id,
|
|
||||||
sender,
|
|
||||||
unsigned,
|
|
||||||
}) if sdp == "Hello" && call_id == "foofoo" && version == UInt::new(1).unwrap()
|
|
||||||
&& event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
|
||||||
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
|
|
||||||
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
|
|
||||||
&& sender == UserId::try_from("@carl:example.com").unwrap()
|
|
||||||
&& unsigned.is_empty()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_message_event() {
|
|
||||||
let aliases_event = AnyMessageEvent::Sticker(MessageEvent {
|
|
||||||
content: StickerEventContent {
|
|
||||||
body: "Hello".into(),
|
|
||||||
info: ImageInfo {
|
|
||||||
height: UInt::new(423),
|
|
||||||
width: UInt::new(1011),
|
|
||||||
mimetype: Some("image/png".into()),
|
|
||||||
size: UInt::new(84242),
|
|
||||||
thumbnail_info: Some(Box::new(ThumbnailInfo {
|
|
||||||
width: UInt::new(800),
|
|
||||||
height: UInt::new(334),
|
|
||||||
mimetype: Some("image/png".into()),
|
|
||||||
size: UInt::new(82595),
|
|
||||||
})),
|
|
||||||
thumbnail_url: Some("mxc://matrix.org".into()),
|
|
||||||
thumbnail_file: None,
|
|
||||||
},
|
|
||||||
url: "http://www.matrix.org".into(),
|
|
||||||
},
|
|
||||||
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
|
|
||||||
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
|
|
||||||
room_id: RoomId::try_from("!roomid:room.com").unwrap(),
|
|
||||||
sender: UserId::try_from("@carl:example.com").unwrap(),
|
|
||||||
unsigned: UnsignedData::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let actual = to_json_value(&aliases_event).unwrap();
|
|
||||||
let expected = json!({
|
|
||||||
"content": {
|
|
||||||
"body": "Hello",
|
|
||||||
"info": {
|
|
||||||
"h": 423,
|
|
||||||
"mimetype": "image/png",
|
|
||||||
"size": 84242,
|
|
||||||
"thumbnail_info": {
|
|
||||||
"h": 334,
|
|
||||||
"mimetype": "image/png",
|
|
||||||
"size": 82595,
|
|
||||||
"w": 800
|
|
||||||
},
|
|
||||||
"thumbnail_url": "mxc://matrix.org",
|
|
||||||
"w": 1011
|
|
||||||
},
|
|
||||||
"url": "http://www.matrix.org"
|
|
||||||
},
|
|
||||||
"event_id": "$h29iv0s8:example.com",
|
|
||||||
"origin_server_ts": 1,
|
|
||||||
"room_id": "!roomid:room.com",
|
|
||||||
"sender": "@carl:example.com",
|
|
||||||
"type": "m.sticker",
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
use ruma_events_macros::event_enum;
|
use ruma_events_macros::event_content_enum;
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
/// Any basic event.
|
/// Any basic event.
|
||||||
name: AnyBasicEvent,
|
name: AnyBasicEventContent,
|
||||||
events: [
|
events: [
|
||||||
"m.direct",
|
"m.direct",
|
||||||
"m.dummy",
|
"m.dummy",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use ruma_events_macros::event_enum;
|
use ruma_events_macros::event_content_enum;
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
name: InvalidEvent,
|
name: InvalidEvent,
|
||||||
events: [
|
events: [
|
||||||
"m.not.a.path",
|
"m.not.a.path",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
event_enum! {
|
event_content_enum! {
|
||||||
name: InvalidEvent,
|
name: InvalidEvent,
|
||||||
events: [
|
events: [
|
||||||
"not.a.path",
|
"not.a.path",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
error: proc macro panicked
|
error: proc macro panicked
|
||||||
--> $DIR/08-enum-invalid-path.rs:10:1
|
--> $DIR/08-enum-invalid-path.rs:10:1
|
||||||
|
|
|
|
||||||
10 | / event_enum! {
|
10 | / event_content_enum! {
|
||||||
11 | | name: InvalidEvent,
|
11 | | name: InvalidEvent,
|
||||||
12 | | events: [
|
12 | | events: [
|
||||||
13 | | "not.a.path",
|
13 | | "not.a.path",
|
||||||
@ -9,9 +9,7 @@ error: proc macro panicked
|
|||||||
15 | | }
|
15 | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
= help: message: assertion failed: `(left == right)`
|
= help: message: well-known matrix events have to start with `m.` found `not.a.path`
|
||||||
left: `"no"`,
|
|
||||||
right: `"m."`: well-known matrix events have to start with `m.`
|
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `not` in `ruma_events`
|
error[E0433]: failed to resolve: could not find `not` in `ruma_events`
|
||||||
--> $DIR/08-enum-invalid-path.rs:6:9
|
--> $DIR/08-enum-invalid-path.rs:6:9
|
||||||
|
Loading…
x
Reference in New Issue
Block a user