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