Add derive macro for StateEventContent
This commit is contained in:
parent
27a9b36499
commit
ef6e2e7023
@ -80,15 +80,25 @@ impl ToTokens for RumaEvent {
|
||||
// let attrs = &self.attrs;
|
||||
let content_name = &self.content_name;
|
||||
// let event_fields = &self.fields;
|
||||
let event_type = &self.event_type;
|
||||
|
||||
let name = &self.name;
|
||||
let content_docstring = format!("The payload for `{}`.", name);
|
||||
|
||||
let content = match &self.content {
|
||||
Content::Struct(fields) => {
|
||||
// TODO this will all be removed so this is only temp
|
||||
let event_content_derive = match self.kind {
|
||||
EventKind::StateEvent => quote! {
|
||||
#[derive(::ruma_events_macros::StateEventContent)]
|
||||
#[ruma_event(type = #event_type)]
|
||||
},
|
||||
EventKind::RoomEvent | EventKind::Event => TokenStream::new(),
|
||||
};
|
||||
quote! {
|
||||
#[doc = #content_docstring]
|
||||
#[derive(Clone, Debug, serde::Serialize, ::ruma_events_macros::FromRaw)]
|
||||
#[derive(Clone, Debug, ::serde::Serialize, ::ruma_events_macros::FromRaw)]
|
||||
#event_content_derive
|
||||
pub struct #content_name {
|
||||
#(#fields),*
|
||||
}
|
||||
@ -105,8 +115,6 @@ impl ToTokens for RumaEvent {
|
||||
}
|
||||
};
|
||||
|
||||
// let event_type_name = self.event_type.value();
|
||||
|
||||
content.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,14 @@ use proc_macro::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
use self::{from_raw::expand_from_raw, gen::RumaEvent, parse::RumaEventInput};
|
||||
use self::{
|
||||
from_raw::expand_from_raw, gen::RumaEvent, parse::RumaEventInput, state::expand_state_event,
|
||||
};
|
||||
|
||||
mod from_raw;
|
||||
mod gen;
|
||||
mod parse;
|
||||
mod state;
|
||||
|
||||
// A note about the `example` modules that appears in doctests:
|
||||
//
|
||||
@ -145,3 +148,12 @@ pub fn derive_from_raw(input: TokenStream) -> TokenStream {
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Generates an implementation of `ruma_events::StateEventContent` and it's super traits.
|
||||
#[proc_macro_derive(StateEventContent, attributes(ruma_event))]
|
||||
pub fn derive_state_event_content(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
expand_state_event(input)
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ pub struct RumaEventInput {
|
||||
/// The name of the event.
|
||||
pub name: Ident,
|
||||
|
||||
/// The kind of event, determiend by the `kind` field.
|
||||
/// The kind of event, determined by the `kind` field.
|
||||
pub kind: EventKind,
|
||||
|
||||
/// The value for the `type` field in the JSON representation of this event. There needs to be a
|
||||
|
78
ruma-events-macros/src/state.rs
Normal file
78
ruma-events-macros/src/state.rs
Normal file
@ -0,0 +1,78 @@
|
||||
//! Implementation of the `StateEventContent` derive macro
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
DeriveInput, LitStr, Token,
|
||||
};
|
||||
|
||||
/// Parses attributes for `*EventContent` derives.
|
||||
///
|
||||
/// `#[ruma_event(type = "m.room.alias")]`
|
||||
enum EventMeta {
|
||||
/// Variant holds the "m.room.whatever" event type.
|
||||
Type(LitStr),
|
||||
}
|
||||
|
||||
impl Parse for EventMeta {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
input.parse::<Token![type]>()?;
|
||||
input.parse::<Token![=]>()?;
|
||||
Ok(EventMeta::Type(input.parse::<LitStr>()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `StateEventContent` implementation for a struct
|
||||
pub fn expand_state_event(input: DeriveInput) -> syn::Result<TokenStream> {
|
||||
let ident = &input.ident;
|
||||
|
||||
let event_type_attr = input
|
||||
.attrs
|
||||
.iter()
|
||||
.find(|attr| attr.path.is_ident("ruma_event"))
|
||||
.ok_or_else(|| {
|
||||
let msg = "no event type attribute found, \
|
||||
add `#[ruma_events(type = \"any.room.event\")]` \
|
||||
below the event content derive";
|
||||
|
||||
syn::Error::new(Span::call_site(), msg)
|
||||
})?;
|
||||
|
||||
let event_type = {
|
||||
let event_meta = event_type_attr.parse_args::<EventMeta>()?;
|
||||
let EventMeta::Type(lit) = event_meta;
|
||||
lit
|
||||
};
|
||||
|
||||
let event_content_impl = quote! {
|
||||
impl ::ruma_events::EventContent for #ident {
|
||||
fn event_type(&self) -> &str {
|
||||
#event_type
|
||||
}
|
||||
|
||||
fn from_parts(
|
||||
ev_type: &str,
|
||||
content: Box<::serde_json::value::RawValue>
|
||||
) -> Result<Self, ::ruma_events::InvalidEvent> {
|
||||
if ev_type != #event_type {
|
||||
return Err(::ruma_events::InvalidEvent {
|
||||
kind: ::ruma_events::error::InvalidEventKind::Deserialization,
|
||||
message: format!("expected `{}` found {}", #event_type, ev_type),
|
||||
});
|
||||
}
|
||||
|
||||
let ev_json = ::ruma_events::EventJson::from(content);
|
||||
ev_json.deserialize()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
#event_content_impl
|
||||
|
||||
impl ::ruma_events::RoomEventContent for #ident { }
|
||||
|
||||
impl ::ruma_events::StateEventContent for #ident { }
|
||||
})
|
||||
}
|
@ -20,25 +20,3 @@ ruma_event! {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl EventContent for AliasesEventContent {
|
||||
fn event_type(&self) -> &str {
|
||||
"m.room.aliases"
|
||||
}
|
||||
|
||||
fn from_parts(event_type: &str, content: Box<RawJsonValue>) -> Result<Self, InvalidEvent> {
|
||||
if event_type != "m.room.aliases" {
|
||||
return Err(InvalidEvent {
|
||||
kind: InvalidEventKind::Deserialization,
|
||||
message: format!("expected `m.room.aliases` found {}", event_type),
|
||||
});
|
||||
}
|
||||
|
||||
let ev_json = EventJson::from(content);
|
||||
ev_json.deserialize()
|
||||
}
|
||||
}
|
||||
|
||||
impl RoomEventContent for AliasesEventContent {}
|
||||
|
||||
impl StateEventContent for AliasesEventContent {}
|
||||
|
@ -27,25 +27,3 @@ ruma_event! {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl EventContent for AvatarEventContent {
|
||||
fn event_type(&self) -> &str {
|
||||
"m.room.avatar"
|
||||
}
|
||||
|
||||
fn from_parts(event_type: &str, content: Box<RawJsonValue>) -> Result<Self, InvalidEvent> {
|
||||
if event_type != "m.room.avatar" {
|
||||
return Err(InvalidEvent {
|
||||
kind: InvalidEventKind::Deserialization,
|
||||
message: format!("expected `m.room.avatar` found {}", event_type),
|
||||
});
|
||||
}
|
||||
|
||||
let ev_json = EventJson::from(content);
|
||||
ev_json.deserialize()
|
||||
}
|
||||
}
|
||||
|
||||
impl RoomEventContent for AvatarEventContent {}
|
||||
|
||||
impl StateEventContent for AvatarEventContent {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user