ruma-events-macros
This commit is contained in:
commit
65bd8e86cc
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
15
.travis.yml
Normal file
15
.travis.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
language: "rust"
|
||||||
|
before_script:
|
||||||
|
- "rustup component add rustfmt"
|
||||||
|
- "rustup component add clippy"
|
||||||
|
script:
|
||||||
|
- "cargo fmt --all -- --check"
|
||||||
|
- "cargo clippy --all-targets --all-features -- -D warnings"
|
||||||
|
- "cargo build --verbose"
|
||||||
|
- "cargo test --verbose"
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
irc:
|
||||||
|
channels:
|
||||||
|
- secure: "HvfXk7XMbm+iDeGoNNO886q4xMOUqJncfAxqklG6FJMCVxyrf8afyyXveCxnTH1F5oDvJXw33m6YetEj1oc7RQcB3+36XkxhjC/IzmupfD9KsikGiamL9YDrfQopvY4RXqodTR3YEof7SkFkEAzuobT0QStemX6TCkC9a7BX1QpMvEbo1pS5wlswy2G2WDbiicoiS93su73AKTQ2jOmzFdwUDZdhpNnPNJqVm5TM2Am8tj6hbX6A2y2AecRZISf8rv8LhmgpZi97NjeeK4CbsQO7G4KANGr8RA7oxlgzbW2q7FbDupB6+zLT4a4/R5GjtJoi8pvaJSL9r2GYpP4VLTYF3+tJVfLbvmQVtUjhHE4masGYfnZgpgRtiH6o+DiF/ErSE/SjJEy/S8ujqXS9mjLFtSg6nLM4k4JdCr7MLrX0buNUsv5mtmhyUvYgJtd9E+ZxLHV5TG5lF28JPMrpKrEE5UvQr/xHZh+70AwCTI5jMoSPqpBwsyQ1agxTIDmiyuo60FhVUoLyiXn25m0ZIf7v1sg4A8vFq0zA9xnhpxtZATXa7StZQn1BH2k82kuyO0hkbFhEHTv25sWJdtaFy/vmrGdchxVy7ogdOXOjXkeg+0oAnOHMsRyZlVusQ4mixM/PYet860XNcW4P6P9Nz0u5ZNmagggXSKCpCqs3smY="
|
||||||
|
use_notice: true
|
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
authors = ["Jimmy Cuadra <jimmy@jimmycuadra.com>"]
|
||||||
|
categories = ["api-bindings", "web-programming"]
|
||||||
|
description = "A procedural macro used by the ruma-events crate."
|
||||||
|
documentation = "https://docs.rs/ruma-events-macros"
|
||||||
|
edition = "2018"
|
||||||
|
homepage = "https://github.com/ruma/ruma-events-macros"
|
||||||
|
keywords = ["matrix", "chat", "messaging", "ruma"]
|
||||||
|
license = "MIT"
|
||||||
|
name = "ruma-events-macros"
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://github.com/ruma/ruma-api-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = { version = "0.15.36", features = ["full"] }
|
||||||
|
quote = "0.6.12"
|
||||||
|
proc-macro2 = "0.4.30"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2019 Jimmy Cuadra
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# ruma-events-macros
|
||||||
|
|
||||||
|
[](https://travis-ci.org/ruma/ruma-events-macros)
|
||||||
|
|
||||||
|
**ruma-events-macros** provides a procedural macro for easily generating event types for [ruma-events](https://github.com/ruma/ruma-events).
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
ruma-events-macros has [comprehensive documentation](https://docs.rs/ruma-events-macros) available on docs.rs.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](http://opensource.org/licenses/MIT)
|
318
src/event.rs
Normal file
318
src/event.rs
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
//! Details of the `ruma_event` procedural macro.
|
||||||
|
|
||||||
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
|
||||||
|
use quote::{quote, ToTokens};
|
||||||
|
use syn::{
|
||||||
|
braced,
|
||||||
|
parse::{self, Parse, ParseStream},
|
||||||
|
punctuated::Punctuated,
|
||||||
|
token::Colon,
|
||||||
|
Attribute, Expr, Field, FieldValue, Ident, Member, Path, PathArguments, PathSegment, Token,
|
||||||
|
TypePath,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The result of processing the `ruma_event` macro, ready for output back to source code.
|
||||||
|
pub struct RumaEvent;
|
||||||
|
|
||||||
|
impl From<RumaEventInput> for RumaEvent {
|
||||||
|
// TODO: Provide an actual impl for this.
|
||||||
|
fn from(_input: RumaEventInput) -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for RumaEvent {
|
||||||
|
// TODO: Provide an actual impl for this.
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let output = quote!(
|
||||||
|
pub struct Foo {}
|
||||||
|
);
|
||||||
|
|
||||||
|
output.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The entire `ruma_event!` macro structure directly as it appears in the source code..
|
||||||
|
pub struct RumaEventInput {
|
||||||
|
/// Outer attributes on the field, such as a docstring.
|
||||||
|
pub attrs: Vec<Attribute>,
|
||||||
|
|
||||||
|
/// The name of the field.
|
||||||
|
pub name: Ident,
|
||||||
|
|
||||||
|
/// The kind of event, determiend by the `kind` field.
|
||||||
|
pub kind: EventKind,
|
||||||
|
|
||||||
|
/// The variant of `ruma_events::EventType` for this event, determined by the `event_type`
|
||||||
|
/// field.
|
||||||
|
pub event_type: Path,
|
||||||
|
|
||||||
|
/// Additional named struct fields in the top level event struct.
|
||||||
|
pub fields: Option<Vec<Field>>,
|
||||||
|
|
||||||
|
/// A struct definition or type alias to be used as the event's `content` field.
|
||||||
|
pub content: Content,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for RumaEventInput {
|
||||||
|
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||||
|
let attrs = input.call(Attribute::parse_outer)?;
|
||||||
|
let name: Ident = input.parse()?;
|
||||||
|
let body;
|
||||||
|
braced!(body in input);
|
||||||
|
|
||||||
|
let mut kind = None;
|
||||||
|
let mut event_type = None;
|
||||||
|
let mut fields = None;
|
||||||
|
let mut content = None;
|
||||||
|
|
||||||
|
#[allow(clippy::identity_conversion)]
|
||||||
|
for field_value_inline_struct in
|
||||||
|
body.parse_terminated::<RumaEventField, Token![,]>(RumaEventField::parse)?
|
||||||
|
{
|
||||||
|
match field_value_inline_struct {
|
||||||
|
RumaEventField::Block(field_block) => {
|
||||||
|
let ident = match field_block.member {
|
||||||
|
Member::Named(ident) => ident,
|
||||||
|
Member::Unnamed(_) => panic!("fields with block values in `ruma_event!` must named `content_type_alias`"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if ident == "content_type_alias" {
|
||||||
|
content = Some(Content::Typedef(field_block.typedef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RumaEventField::InlineStruct(field_inline_struct) => {
|
||||||
|
let ident = match field_inline_struct.member {
|
||||||
|
Member::Named(ident) => ident,
|
||||||
|
Member::Unnamed(_) => panic!("fields with inline struct values in `ruma_event!` must be named `fields` or `content`."),
|
||||||
|
};
|
||||||
|
|
||||||
|
if ident == "fields" {
|
||||||
|
fields = Some(field_inline_struct.fields);
|
||||||
|
} else if ident == "content" {
|
||||||
|
content = Some(Content::Struct(field_inline_struct.fields));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RumaEventField::Value(field_value) => {
|
||||||
|
let ident = match field_value.member {
|
||||||
|
Member::Named(ident) => ident,
|
||||||
|
Member::Unnamed(_) => panic!("fields with expression values in `ruma_event!` must be named `kind` or `event_type`, ."),
|
||||||
|
};
|
||||||
|
|
||||||
|
if ident == "kind" {
|
||||||
|
let event_kind = match field_value.expr {
|
||||||
|
Expr::Path(expr_path) => {
|
||||||
|
if expr_path
|
||||||
|
.path
|
||||||
|
.is_ident(Ident::new("Event", Span::call_site()))
|
||||||
|
{
|
||||||
|
EventKind::Event
|
||||||
|
} else if expr_path
|
||||||
|
.path
|
||||||
|
.is_ident(Ident::new("RoomEvent", Span::call_site()))
|
||||||
|
{
|
||||||
|
EventKind::RoomEvent
|
||||||
|
} else if expr_path
|
||||||
|
.path
|
||||||
|
.is_ident(Ident::new("StateEvent", Span::call_site()))
|
||||||
|
{
|
||||||
|
EventKind::StateEvent
|
||||||
|
} else {
|
||||||
|
panic!("value of field `kind` must be one of `Event`, `RoomEvent`, or `StateEvent`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"value of field `kind` is required to be an ident by `ruma_event!`"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
kind = Some(event_kind);
|
||||||
|
} else if ident == "event_type" {
|
||||||
|
match field_value.expr {
|
||||||
|
Expr::Path(expr_path) => {
|
||||||
|
if expr_path.path.segments.len() != 1 {
|
||||||
|
panic!("value of field `event_type` is required to be an ident by `ruma_event!`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = expr_path.path;
|
||||||
|
let variant = path.segments.first().unwrap().into_value();
|
||||||
|
|
||||||
|
let mut punctuated = Punctuated::new();
|
||||||
|
punctuated.push(PathSegment {
|
||||||
|
ident: Ident::new("crate", Span::call_site()),
|
||||||
|
arguments: PathArguments::None,
|
||||||
|
});
|
||||||
|
punctuated.push(PathSegment {
|
||||||
|
ident: Ident::new("EventType", Span::call_site()),
|
||||||
|
arguments: PathArguments::None,
|
||||||
|
});
|
||||||
|
punctuated.push(variant.clone());
|
||||||
|
|
||||||
|
event_type = Some(Path {
|
||||||
|
leading_colon: None,
|
||||||
|
segments: punctuated,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"value of field `event_type` is required to be an ident by `ruma_event!`"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("unexpected field-value pair with field name `{}`", ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind.is_none() {
|
||||||
|
panic!("field `kind` is required by `ruma_event!`");
|
||||||
|
} else if event_type.is_none() {
|
||||||
|
panic!("field `event_type` is required by `ruma_event!`");
|
||||||
|
} else if content.is_none() {
|
||||||
|
panic!(
|
||||||
|
"one field named `content` or `content_type_alias` is required by `ruma_event!`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
attrs,
|
||||||
|
name,
|
||||||
|
kind: kind.unwrap(),
|
||||||
|
event_type: event_type.unwrap(),
|
||||||
|
fields,
|
||||||
|
content: content.unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Which kind of event is being generated.
|
||||||
|
///
|
||||||
|
/// Determined by the `kind` field in the macro body.
|
||||||
|
pub enum EventKind {
|
||||||
|
/// A basic event.
|
||||||
|
Event,
|
||||||
|
|
||||||
|
/// A room event.
|
||||||
|
RoomEvent,
|
||||||
|
|
||||||
|
/// A state event.
|
||||||
|
StateEvent,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information for generating the type used for the event's `content` field.
|
||||||
|
pub enum Content {
|
||||||
|
/// A struct, e.g. `ExampleEventContent { ... }`.
|
||||||
|
Struct(Vec<Field>),
|
||||||
|
|
||||||
|
/// A type alias, e.g. `type ExampleEventContent = SomeExistingType`
|
||||||
|
Typedef(Typedef),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The style of field within the macro body.
|
||||||
|
enum RumaEventField {
|
||||||
|
/// The value of a field is a block with a type alias in it.
|
||||||
|
///
|
||||||
|
/// Used for `content_type_alias`.
|
||||||
|
Block(FieldBlock),
|
||||||
|
|
||||||
|
/// The value of a field is a block with named struct fields in it.
|
||||||
|
///
|
||||||
|
/// Used for `content`.
|
||||||
|
InlineStruct(FieldInlineStruct),
|
||||||
|
|
||||||
|
/// A standard named struct field.
|
||||||
|
///
|
||||||
|
/// Used for `kind` and `event_type`.
|
||||||
|
Value(FieldValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for RumaEventField {
|
||||||
|
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||||
|
let ahead = input.fork();
|
||||||
|
let field_ident: Ident = ahead.parse()?;
|
||||||
|
|
||||||
|
match field_ident.to_string().as_ref() {
|
||||||
|
"content" | "fields" => {
|
||||||
|
let attrs = input.call(Attribute::parse_outer)?;
|
||||||
|
let member = input.parse()?;
|
||||||
|
let colon_token = input.parse()?;
|
||||||
|
let body;
|
||||||
|
braced!(body in input);
|
||||||
|
let fields = body
|
||||||
|
.parse_terminated::<Field, Token![,]>(Field::parse_named)?
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(RumaEventField::InlineStruct(FieldInlineStruct {
|
||||||
|
attrs,
|
||||||
|
member,
|
||||||
|
colon_token,
|
||||||
|
fields,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
"content_type_alias" => Ok(RumaEventField::Block(FieldBlock {
|
||||||
|
attrs: input.call(Attribute::parse_outer)?,
|
||||||
|
member: input.parse()?,
|
||||||
|
colon_token: input.parse()?,
|
||||||
|
typedef: input.parse()?,
|
||||||
|
})),
|
||||||
|
_ => Ok(RumaEventField::Value(input.parse()?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value of a field is a block with a type alias in it.
|
||||||
|
///
|
||||||
|
/// Used for `content_type_alias`.
|
||||||
|
struct FieldBlock {
|
||||||
|
/// Outer attributes on the field, such as a docstring.
|
||||||
|
pub attrs: Vec<Attribute>,
|
||||||
|
|
||||||
|
/// The name of the field.
|
||||||
|
pub member: Member,
|
||||||
|
|
||||||
|
/// The colon that appears between the field name and type.
|
||||||
|
pub colon_token: Colon,
|
||||||
|
|
||||||
|
/// The path to the type that will be used in a type alias for the event's `content` type.
|
||||||
|
pub typedef: Typedef,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value of a field is a block with named struct fields in it.
|
||||||
|
///
|
||||||
|
/// Used for `content`.
|
||||||
|
struct FieldInlineStruct {
|
||||||
|
/// Outer attributes on the field, such as a docstring.
|
||||||
|
pub attrs: Vec<Attribute>,
|
||||||
|
|
||||||
|
/// The name of the field.
|
||||||
|
pub member: Member,
|
||||||
|
|
||||||
|
/// The colon that appears between the field name and type.
|
||||||
|
pub colon_token: Colon,
|
||||||
|
|
||||||
|
/// The fields that define the `content` struct.
|
||||||
|
pub fields: Vec<Field>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Path to a type to be used in a type alias for an event's `content` type.
|
||||||
|
pub struct Typedef {
|
||||||
|
/// Outer attributes on the field, such as a docstring.
|
||||||
|
pub attrs: Vec<Attribute>,
|
||||||
|
|
||||||
|
/// Path to the type.
|
||||||
|
pub path: TypePath,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Typedef {
|
||||||
|
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||||
|
let body;
|
||||||
|
braced!(body in input);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
attrs: body.call(Attribute::parse_outer)?,
|
||||||
|
path: body.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
134
src/lib.rs
Normal file
134
src/lib.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
//! Crate `ruma-events-macros` provides a procedural macro for generating
|
||||||
|
//! [ruma-events](https://github.com/ruma/ruma-events) events.
|
||||||
|
//!
|
||||||
|
//! See the documentation for the `ruma_event!` macro for usage details.
|
||||||
|
//!
|
||||||
|
#![deny(
|
||||||
|
missing_copy_implementations,
|
||||||
|
missing_debug_implementations,
|
||||||
|
// missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
|
||||||
|
warnings
|
||||||
|
)]
|
||||||
|
#![warn(
|
||||||
|
clippy::empty_line_after_outer_attr,
|
||||||
|
clippy::expl_impl_clone_on_copy,
|
||||||
|
clippy::if_not_else,
|
||||||
|
clippy::items_after_statements,
|
||||||
|
clippy::match_same_arms,
|
||||||
|
clippy::mem_forget,
|
||||||
|
clippy::missing_docs_in_private_items,
|
||||||
|
clippy::multiple_inherent_impl,
|
||||||
|
clippy::mut_mut,
|
||||||
|
clippy::needless_borrow,
|
||||||
|
clippy::needless_continue,
|
||||||
|
clippy::single_match_else,
|
||||||
|
clippy::unicode_not_nfc,
|
||||||
|
clippy::use_self,
|
||||||
|
clippy::used_underscore_binding,
|
||||||
|
clippy::wrong_pub_self_convention,
|
||||||
|
clippy::wrong_self_convention
|
||||||
|
)]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::ToTokens;
|
||||||
|
|
||||||
|
use crate::event::{RumaEvent, RumaEventInput};
|
||||||
|
|
||||||
|
mod event;
|
||||||
|
|
||||||
|
// A note about the `example` modules that appears in doctests:
|
||||||
|
//
|
||||||
|
// This is necessary because otherwise the expanded code appears in function context, which makes
|
||||||
|
// the compiler interpret the output of the macro as a statement, and proc macros currently aren't
|
||||||
|
// allowed to expand to statements, resulting in a compiler error.
|
||||||
|
|
||||||
|
/// Generates a Rust type for a Matrix event.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// The most common form of event is a struct with all the standard fields for an event of its
|
||||||
|
/// kind and a struct for its `content` field:
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// # pub mod example {
|
||||||
|
/// # use ruma_events_macros::ruma_event;
|
||||||
|
/// ruma_event! {
|
||||||
|
/// /// Informs the room about what room aliases it has been given.
|
||||||
|
/// AliasesEvent {
|
||||||
|
/// kind: StateEvent,
|
||||||
|
/// event_type: RoomAliases,
|
||||||
|
/// content: {
|
||||||
|
/// /// A list of room aliases.
|
||||||
|
/// pub aliases: Vec<RoomAliasId>,
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Occasionally an event will have non-standard fields at its top level (outside the `content`
|
||||||
|
/// field). These extra fields are declared in block labeled with `fields`:
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// # pub mod example {
|
||||||
|
/// # use ruma_events_macros::ruma_event;
|
||||||
|
/// ruma_event! {
|
||||||
|
/// /// A redaction of an event.
|
||||||
|
/// RedactionEvent {
|
||||||
|
/// kind: RoomEvent,
|
||||||
|
/// event_type: RoomRedaction,
|
||||||
|
/// fields: {
|
||||||
|
/// /// The ID of the event that was redacted.
|
||||||
|
/// pub redacts: EventId
|
||||||
|
/// },
|
||||||
|
/// content: {
|
||||||
|
/// /// The reason for the redaction, if any.
|
||||||
|
/// pub reason: Option<String>,
|
||||||
|
/// },
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Sometimes the type of the `content` should be a type alias rather than a struct or enum. This
|
||||||
|
/// is designated with `content_type_alias`:
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// # pub mod example {
|
||||||
|
/// # use ruma_events_macros::ruma_event;
|
||||||
|
/// ruma_event! {
|
||||||
|
/// /// Informs the client about the rooms that are considered direct by a user.
|
||||||
|
/// DirectEvent {
|
||||||
|
/// kind: Event,
|
||||||
|
/// event_type: Direct,
|
||||||
|
/// content_type_alias: {
|
||||||
|
/// /// The payload of a `DirectEvent`.
|
||||||
|
/// ///
|
||||||
|
/// /// A mapping of `UserId`'s to a collection of `RoomId`'s which are considered
|
||||||
|
/// /// *direct* for that particular user.
|
||||||
|
/// HashMap<UserId, Vec<RoomId>>
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If `content` and `content_type_alias` are both supplied, the second one listed will overwrite
|
||||||
|
/// the first.
|
||||||
|
///
|
||||||
|
/// The event type and content type will have copies generated inside a private `raw` module. These
|
||||||
|
/// "raw" versions are the same, except they implement `serde::Deserialize`. An inherent method
|
||||||
|
/// called `from_str` will be generated for the event type that takes a `&str` of JSON and attempts
|
||||||
|
/// to deserialize the type using the "raw" version. If deserialization fails, an error is returned
|
||||||
|
/// to the user. If deserialization succeeds, a value of the public event type will be populated
|
||||||
|
/// from the raw version's fields and returned.
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn ruma_event(input: TokenStream) -> TokenStream {
|
||||||
|
let ruma_event_input = syn::parse_macro_input!(input as RumaEventInput);
|
||||||
|
|
||||||
|
let ruma_event = RumaEvent::from(ruma_event_input);
|
||||||
|
|
||||||
|
ruma_event.into_token_stream().into()
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user