diff --git a/ruma-events-macros/src/event_enum.rs b/ruma-events-macros/src/event_enum.rs index 0804eff9..319388a5 100644 --- a/ruma-events-macros/src/event_enum.rs +++ b/ruma-events-macros/src/event_enum.rs @@ -2,10 +2,9 @@ use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; -use syn::{ - parse::{self, Parse, ParseStream}, - Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token, -}; +use syn::{Attribute, Ident, LitStr}; + +use crate::event_parse::{EventEnumInput, EventKind, EventKindVariation}; fn is_non_stripped_room_event(kind: &EventKind, var: &EventKindVariation) -> bool { matches!(kind, EventKind::Message(_) | EventKind::State(_)) @@ -688,150 +687,3 @@ fn field_return_type(name: &str, var: &EventKindVariation) -> TokenStream { _ => panic!("the `ruma_events_macros::event_enum::EVENT_FIELD` const was changed"), } } - -/// Custom keywords for the `event_enum!` macro -mod kw { - syn::custom_keyword!(kind); - syn::custom_keyword!(events); -} - -// If the variants of this enum change `to_event_path` needs to be updated as well. -#[derive(Eq, PartialEq)] -enum EventKindVariation { - Full, - Sync, - Stripped, - Redacted, - RedactedSync, - RedactedStripped, -} - -// If the variants of this enum change `to_event_path` needs to be updated as well. -enum EventKind { - Basic(Ident), - Ephemeral(Ident), - Message(Ident), - State(Ident), - ToDevice(Ident), -} - -impl EventKind { - fn is_state(&self) -> bool { - matches!(self, Self::State(_)) - } - - fn is_message(&self) -> bool { - matches!(self, Self::Message(_)) - } - - fn to_event_ident(&self, var: &EventKindVariation) -> Option { - use EventKindVariation::*; - - match (self, var) { - // all `EventKind`s are valid event structs and event enums. - (_, Full) => Some(format_ident!("{}Event", self.get_ident())), - (Self::Ephemeral(i), Sync) | (Self::Message(i), Sync) | (Self::State(i), Sync) => { - Some(format_ident!("Sync{}Event", i)) - } - (Self::State(i), Stripped) => Some(format_ident!("Stripped{}Event", i)), - (Self::Message(i), Redacted) | (Self::State(i), Redacted) => { - Some(format_ident!("Redacted{}Event", i)) - } - (Self::Message(i), RedactedSync) | (Self::State(i), RedactedSync) => { - Some(format_ident!("RedactedSync{}Event", i)) - } - (Self::State(i), RedactedStripped) => Some(format_ident!("RedactedStripped{}Event", i)), - _ => None, - } - } - - fn to_event_enum_ident(&self, var: &EventKindVariation) -> Option { - Some(format_ident!("Any{}", self.to_event_ident(var)?)) - } - - /// `Any[kind]EventContent` - fn to_content_enum(&self) -> Ident { - format_ident!("Any{}EventContent", self.get_ident()) - } - - fn get_ident(&self) -> &Ident { - match self { - EventKind::Basic(i) - | EventKind::Ephemeral(i) - | EventKind::Message(i) - | EventKind::State(i) - | EventKind::ToDevice(i) => i, - } - } -} - -impl Parse for EventKind { - fn parse(input: ParseStream) -> syn::Result { - let ident = input.parse::()?; - Ok(match ident.to_string().as_str() { - "Basic" => EventKind::Basic(ident), - "EphemeralRoom" => EventKind::Ephemeral(ident), - "Message" => EventKind::Message(ident), - "State" => EventKind::State(ident), - "ToDevice" => EventKind::ToDevice(ident), - id => { - return Err(syn::Error::new( - input.span(), - format!( - "valid event kinds are Basic, EphemeralRoom, Message, State, ToDevice found `{}`", - id - ), - )); - } - }) - } -} - -/// 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. - attrs: Vec, - - /// The name of the event. - name: EventKind, - - /// 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). - events: Vec, -} - -impl Parse for EventEnumInput { - fn parse(input: ParseStream<'_>) -> parse::Result { - let attrs = input.call(Attribute::parse_outer)?; - // "name" field - input.parse::()?; - input.parse::()?; - - // the name of our event enum - let name = input.parse::()?; - input.parse::()?; - - // "events" field - input.parse::()?; - input.parse::()?; - - // an array of event names `["m.room.whatever", ...]` - let ev_array = input.parse::()?; - 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::>()?; - - Ok(Self { attrs, name, events }) - } -} diff --git a/ruma-events-macros/src/event_parse.rs b/ruma-events-macros/src/event_parse.rs new file mode 100644 index 00000000..813c414a --- /dev/null +++ b/ruma-events-macros/src/event_parse.rs @@ -0,0 +1,155 @@ +//! Implementation of event enum and event content enum macros. + +use matches::matches; +use quote::format_ident; +use syn::{ + parse::{self, Parse, ParseStream}, + Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token, +}; + +/// Custom keywords for the `event_enum!` macro +mod kw { + syn::custom_keyword!(kind); + syn::custom_keyword!(events); +} + +// If the variants of this enum change `to_event_path` needs to be updated as well. +#[derive(Eq, PartialEq)] +pub enum EventKindVariation { + Full, + Sync, + Stripped, + Redacted, + RedactedSync, + RedactedStripped, +} + +// If the variants of this enum change `to_event_path` needs to be updated as well. +pub enum EventKind { + Basic(Ident), + Ephemeral(Ident), + Message(Ident), + State(Ident), + ToDevice(Ident), +} + +impl EventKind { + pub fn is_state(&self) -> bool { + matches!(self, Self::State(_)) + } + + pub fn is_message(&self) -> bool { + matches!(self, Self::Message(_)) + } + + pub fn to_event_ident(&self, var: &EventKindVariation) -> Option { + use EventKindVariation::*; + + match (self, var) { + // all `EventKind`s are valid event structs and event enums. + (_, Full) => Some(format_ident!("{}Event", self.get_ident())), + (Self::Ephemeral(i), Sync) | (Self::Message(i), Sync) | (Self::State(i), Sync) => { + Some(format_ident!("Sync{}Event", i)) + } + (Self::State(i), Stripped) => Some(format_ident!("Stripped{}Event", i)), + (Self::Message(i), Redacted) | (Self::State(i), Redacted) => { + Some(format_ident!("Redacted{}Event", i)) + } + (Self::Message(i), RedactedSync) | (Self::State(i), RedactedSync) => { + Some(format_ident!("RedactedSync{}Event", i)) + } + (Self::State(i), RedactedStripped) => Some(format_ident!("RedactedStripped{}Event", i)), + _ => None, + } + } + + pub fn to_event_enum_ident(&self, var: &EventKindVariation) -> Option { + Some(format_ident!("Any{}", self.to_event_ident(var)?)) + } + + /// `Any[kind]EventContent` + pub fn to_content_enum(&self) -> Ident { + format_ident!("Any{}EventContent", self.get_ident()) + } + + pub fn get_ident(&self) -> &Ident { + match self { + EventKind::Basic(i) + | EventKind::Ephemeral(i) + | EventKind::Message(i) + | EventKind::State(i) + | EventKind::ToDevice(i) => i, + } + } +} + +impl Parse for EventKind { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse::()?; + Ok(match ident.to_string().as_str() { + "Basic" => EventKind::Basic(ident), + "EphemeralRoom" => EventKind::Ephemeral(ident), + "Message" => EventKind::Message(ident), + "State" => EventKind::State(ident), + "ToDevice" => EventKind::ToDevice(ident), + id => { + return Err(syn::Error::new( + input.span(), + format!( + "valid event kinds are Basic, EphemeralRoom, Message, State, ToDevice found `{}`", + id + ), + )); + } + }) + } +} + +/// 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, + + /// The name of the event. + pub name: EventKind, + + /// 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, +} + +impl Parse for EventEnumInput { + fn parse(input: ParseStream<'_>) -> parse::Result { + let attrs = input.call(Attribute::parse_outer)?; + // "name" field + input.parse::()?; + input.parse::()?; + + // the name of our event enum + let name = input.parse::()?; + input.parse::()?; + + // "events" field + input.parse::()?; + input.parse::()?; + + // an array of event names `["m.room.whatever", ...]` + let ev_array = input.parse::()?; + 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::>()?; + + Ok(Self { attrs, name, events }) + } +} diff --git a/ruma-events-macros/src/lib.rs b/ruma-events-macros/src/lib.rs index 6c249f27..1ad84155 100644 --- a/ruma-events-macros/src/lib.rs +++ b/ruma-events-macros/src/lib.rs @@ -16,13 +16,14 @@ use self::{ expand_basic_event_content, expand_ephemeral_room_event_content, expand_event_content, expand_message_event_content, expand_room_event_content, expand_state_event_content, }, - event_enum::{expand_event_enum, EventEnumInput}, + event_enum::expand_event_enum, + event_parse::EventEnumInput, }; mod event; mod event_content; mod event_enum; - +mod event_parse; /// Generates an enum to represent the various Matrix event types. /// /// This macro also implements the necessary traits for the type to serialize and deserialize