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 proc_macro2::{Span, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{
|
use syn::{Attribute, Ident, LitStr};
|
||||||
parse::{self, Parse, ParseStream},
|
|
||||||
Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token,
|
use crate::event_parse::{EventEnumInput, EventKind, EventKindVariation};
|
||||||
};
|
|
||||||
|
|
||||||
fn is_non_stripped_room_event(kind: &EventKind, var: &EventKindVariation) -> bool {
|
fn is_non_stripped_room_event(kind: &EventKind, var: &EventKindVariation) -> bool {
|
||||||
matches!(kind, EventKind::Message(_) | EventKind::State(_))
|
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"),
|
_ => 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_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},
|
event_enum::expand_event_enum,
|
||||||
|
event_parse::EventEnumInput,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
mod event_content;
|
mod event_content;
|
||||||
mod event_enum;
|
mod event_enum;
|
||||||
|
mod event_parse;
|
||||||
/// Generates an enum to represent the various Matrix event types.
|
/// Generates an 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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user