Jonas Platte 883a9566d2 Add 'ruma-events-macros/' from commit '659dc963949cdb3d928d9f5d3ed9a49e1e2b6158'
git-subtree-dir: ruma-events-macros
git-subtree-mainline: 91d564dcf812196f7497fe93ea5591eab8d83d1d
git-subtree-split: 659dc963949cdb3d928d9f5d3ed9a49e1e2b6158
2019-09-13 22:17:22 +02:00

140 lines
4.8 KiB
Rust

//! 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
)]
#![recursion_limit = "128"]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::ToTokens;
use crate::{gen::RumaEvent, parse::RumaEventInput};
mod gen;
mod parse;
// 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:
///
/// ```ignore
/// # 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<ruma_identifiers::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`:
///
/// ```ignore
/// # 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: ruma_identifiers::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`:
///
/// ```ignore
/// # 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.
/// std::collections::HashMap<ruma_identifiers::UserId, Vec<ruma_identifiers::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 implementation of
/// `std::str::FromStr` (and for completeness, `std::convert::TryFrom<&str>`) will be provided,
/// which will allow the user to call `parse` on a string slice of JSON data in attempt to convert
/// into the event type. `FromStr` 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. If any
/// semantic error is found after deserialization, a `serde_json::Value` of the deserialized data
/// will be returned in an `InvalidEvent`.
#[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()
}