#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")] #![doc(html_logo_url = "https://www.ruma.io/images/logo.png")] use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, DeriveInput, ItemEnum}; use deserialize_from_cow_str::expand_deserialize_from_cow_str; use display_as_ref_str::expand_display_as_ref_str; use enum_as_ref_str::expand_enum_as_ref_str; use enum_from_string::expand_enum_from_string; use eq_as_ref_str::expand_partial_eq_as_ref_str; use ord_as_ref_str::{expand_ord_as_ref_str, expand_partial_ord_as_ref_str}; use outgoing::expand_derive_outgoing; use serialize_as_ref_str::expand_serialize_as_ref_str; mod attr; mod case; mod deserialize_from_cow_str; mod display_as_ref_str; mod enum_as_ref_str; mod enum_from_string; mod eq_as_ref_str; mod ord_as_ref_str; mod outgoing; mod serialize_as_ref_str; mod util; /// Derive the `Outgoing` trait, possibly generating an 'Incoming' version of the struct this /// derive macro is used on. Specifically, if no lifetime variables are used on any of the fields /// of the struct, this simple implementation will be generated: /// /// ```ignore /// # // TODO: "ignore" this doctest until it is more extensively documented. (See #541) /// impl Outgoing for MyType { /// type Incoming = Self; /// } /// ``` /* TODO: Extend docs. Previously: If, however, `#[wrap_incoming]` is used (which is the only reason you should ever use this derive macro manually), a new struct `IncomingT` (where `T` is the type this derive is used on) is generated, with all of the fields with `#[wrap_incoming]` replaced: ```ignore #[derive(Outgoing)] struct MyType { pub foo: Foo, #[wrap_incoming] pub bar: Bar, #[wrap_incoming(Baz)] pub baz: Option, #[wrap_incoming(with EventResult)] pub x: XEvent, #[wrap_incoming(YEvent with EventResult)] pub ys: Vec, } // generated struct IncomingMyType { pub foo: Foo, pub bar: IncomingBar, pub baz: Option, pub x: EventResult, pub ys: Vec>, } ``` */ #[proc_macro_derive(Outgoing, attributes(incoming_derive))] pub fn derive_outgoing(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_derive_outgoing(input).unwrap_or_else(syn::Error::into_compile_error).into() } #[proc_macro_derive(AsRefStr, attributes(ruma_enum))] pub fn derive_enum_as_ref_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ItemEnum); expand_enum_as_ref_str(&input).unwrap_or_else(syn::Error::into_compile_error).into() } #[proc_macro_derive(FromString, attributes(ruma_enum))] pub fn derive_enum_from_string(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ItemEnum); expand_enum_from_string(&input).unwrap_or_else(syn::Error::into_compile_error).into() } // FIXME: The following macros aren't actually interested in type details beyond name (and possibly // generics in the future). They probably shouldn't use `DeriveInput`. #[proc_macro_derive(DisplayAsRefStr)] pub fn derive_display_as_ref_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_display_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into() } #[proc_macro_derive(SerializeAsRefStr)] pub fn derive_serialize_as_ref_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_serialize_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into() } #[proc_macro_derive(DeserializeFromCowStr)] pub fn derive_deserialize_from_cow_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_deserialize_from_cow_str(&input.ident) .unwrap_or_else(syn::Error::into_compile_error) .into() } #[proc_macro_derive(PartialOrdAsRefStr)] pub fn derive_partial_ord_as_ref_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_partial_ord_as_ref_str(&input.ident) .unwrap_or_else(syn::Error::into_compile_error) .into() } #[proc_macro_derive(OrdAsRefStr)] pub fn derive_ord_as_ref_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_ord_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into() } #[proc_macro_derive(PartialEqAsRefStr)] pub fn derive_partial_eq_as_ref_str(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); expand_partial_eq_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into() } /// Shorthand for the derives `AsRefStr`, `FromString`, `DisplayAsRefStr`, `SerializeAsRefStr` and /// `DeserializeFromCowStr`. #[proc_macro_derive(StringEnum, attributes(ruma_enum))] pub fn derive_string_enum(input: TokenStream) -> TokenStream { fn expand_all(input: ItemEnum) -> syn::Result { let as_ref_str_impl = expand_enum_as_ref_str(&input)?; let from_string_impl = expand_enum_from_string(&input)?; let display_impl = expand_display_as_ref_str(&input.ident)?; let serialize_impl = expand_serialize_as_ref_str(&input.ident)?; let deserialize_impl = expand_deserialize_from_cow_str(&input.ident)?; Ok(quote! { #as_ref_str_impl #from_string_impl #display_impl #serialize_impl #deserialize_impl }) } let input = parse_macro_input!(input as ItemEnum); expand_all(input).unwrap_or_else(syn::Error::into_compile_error).into() } /// A derive macro that generates no code, but registers the serde attribute so both `#[serde(...)]` /// and `#[cfg_attr(..., serde(...))]` are accepted on the type, its fields and (in case the input /// is an enum) variants fields. #[doc(hidden)] #[proc_macro_derive(_FakeDeriveSerde, attributes(serde))] pub fn fake_derive_serde(_input: TokenStream) -> TokenStream { TokenStream::new() }