Use EventKind/Variation in the Event derive macro
Move the event parsing into it's own mod to be shared by event.rs.
This commit is contained in:
parent
080a537664
commit
4b9fdcb189
@ -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<Ident> {
|
||||
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<Ident> {
|
||||
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<Self> {
|
||||
let ident = input.parse::<Ident>()?;
|
||||
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<Attribute>,
|
||||
|
||||
/// 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<LitStr>,
|
||||
}
|
||||
|
||||
impl Parse for EventEnumInput {
|
||||
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
// "name" field
|
||||
input.parse::<kw::kind>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
// the name of our event enum
|
||||
let name = input.parse::<EventKind>()?;
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
155
ruma-events-macros/src/event_parse.rs
Normal file
155
ruma-events-macros/src/event_parse.rs
Normal file
@ -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<Ident> {
|
||||
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<Ident> {
|
||||
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<Self> {
|
||||
let ident = input.parse::<Ident>()?;
|
||||
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<Attribute>,
|
||||
|
||||
/// 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<LitStr>,
|
||||
}
|
||||
|
||||
impl Parse for EventEnumInput {
|
||||
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
// "name" field
|
||||
input.parse::<kw::kind>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
// the name of our event enum
|
||||
let name = input.parse::<EventKind>()?;
|
||||
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 })
|
||||
}
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user