#![doc(html_favicon_url = "https://ruma.dev/favicon.ico")]
#![doc(html_logo_url = "https://ruma.dev/images/logo.png")]
#![cfg_attr(feature = "__internal_macro_expand", feature(proc_macro_expand))]
#![warn(missing_docs)]
#![allow(unreachable_pub)]
#![allow(clippy::derive_partial_eq_without_eq)]
use identifiers::expand_id_zst;
use proc_macro::TokenStream;
use proc_macro2 as pm2;
use quote::quote;
use ruma_identifiers_validation::{
base64_public_key, event_id, mxc_uri, room_alias_id, room_id, room_version_id, server_name,
server_signing_key_version, user_id,
};
use syn::{parse_macro_input, DeriveInput, ItemEnum, ItemStruct};
mod api;
mod events;
mod identifiers;
mod serde;
mod util;
use self::{
api::{
request::{expand_derive_request, expand_request},
response::{expand_derive_response, expand_response},
},
events::{
event::expand_event,
event_content::expand_event_content,
event_enum::{expand_event_enums, expand_from_impls_derived},
event_parse::EventEnumInput,
event_type::expand_event_type_enum,
},
identifiers::IdentifierInput,
serde::{
as_str_as_ref_str::expand_as_str_as_ref_str,
debug_as_ref_str::expand_debug_as_ref_str,
deserialize_from_cow_str::expand_deserialize_from_cow_str,
display_as_ref_str::expand_display_as_ref_str,
enum_as_ref_str::expand_enum_as_ref_str,
enum_from_string::expand_enum_from_string,
eq_as_ref_str::expand_partial_eq_as_ref_str,
ord_as_ref_str::{expand_ord_as_ref_str, expand_partial_ord_as_ref_str},
serialize_as_ref_str::expand_serialize_as_ref_str,
},
util::{import_ruma_common, import_ruma_events},
};
#[proc_macro]
pub fn event_enum(input: TokenStream) -> TokenStream {
let event_enum_input = syn::parse_macro_input!(input as EventEnumInput);
let ruma_common = import_ruma_common();
let enums = event_enum_input
.enums
.iter()
.map(|e| expand_event_enums(e).unwrap_or_else(syn::Error::into_compile_error))
.collect::<pm2::TokenStream>();
let event_types = expand_event_type_enum(event_enum_input, ruma_common)
.unwrap_or_else(syn::Error::into_compile_error);
let tokens = quote! {
#enums
#event_types
};
tokens.into()
}
#[proc_macro_derive(EventContent, attributes(ruma_event))]
pub fn derive_event_content(input: TokenStream) -> TokenStream {
let ruma_events = import_ruma_events();
let input = parse_macro_input!(input as DeriveInput);
expand_event_content(&input, &ruma_events).unwrap_or_else(syn::Error::into_compile_error).into()
}
#[proc_macro_derive(Event, attributes(ruma_event))]
pub fn derive_event(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
expand_event(input).unwrap_or_else(syn::Error::into_compile_error).into()
}
#[proc_macro_derive(EventEnumFromEvent)]
pub fn derive_from_event_to_enum(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
expand_from_impls_derived(input).into()
}
#[proc_macro_derive(IdZst, attributes(ruma_id))]
pub fn derive_id_zst(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
expand_id_zst(input).unwrap_or_else(syn::Error::into_compile_error).into()
}
#[proc_macro]
pub fn event_id(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(event_id::validate(&id.value()).is_ok(), "Invalid event id");
let output = quote! {
<&#dollar_crate::EventId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn room_alias_id(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(room_alias_id::validate(&id.value()).is_ok(), "Invalid room_alias_id");
let output = quote! {
<&#dollar_crate::RoomAliasId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn room_id(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(room_id::validate(&id.value()).is_ok(), "Invalid room_id");
let output = quote! {
<&#dollar_crate::RoomId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn room_version_id(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(room_version_id::validate(&id.value()).is_ok(), "Invalid room_version_id");
let output = quote! {
<#dollar_crate::RoomVersionId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn server_signing_key_version(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(
server_signing_key_version::validate(&id.value()).is_ok(),
"Invalid server_signing_key_version"
);
let output = quote! {
<&#dollar_crate::ServerSigningKeyVersion as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn server_name(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(server_name::validate(&id.value()).is_ok(), "Invalid server_name");
let output = quote! {
<&#dollar_crate::ServerName as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn mxc_uri(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(mxc_uri::validate(&id.value()).is_ok(), "Invalid mxc://");
let output = quote! {
<&#dollar_crate::MxcUri as ::std::convert::From<&str>>::from(#id)
};
output.into()
}
#[proc_macro]
pub fn user_id(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(user_id::validate(&id.value()).is_ok(), "Invalid user_id");
let output = quote! {
<&#dollar_crate::UserId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn base64_public_key(input: TokenStream) -> TokenStream {
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
assert!(base64_public_key::validate(&id.value()).is_ok(), "Invalid base64 public key");
let output = quote! {
<&#dollar_crate::DeviceKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.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()
}
#[proc_macro_derive(AsStrAsRefStr, attributes(ruma_enum))]
pub fn derive_as_str_as_ref_str(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
expand_as_str_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
}
#[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(DebugAsRefStr)]
pub fn derive_debug_as_ref_str(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
expand_debug_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()
}
#[proc_macro_derive(StringEnum, attributes(ruma_enum))]
pub fn derive_string_enum(input: TokenStream) -> TokenStream {
fn expand_all(input: ItemEnum) -> syn::Result<proc_macro2::TokenStream> {
let as_ref_str_impl = expand_enum_as_ref_str(&input)?;
let from_string_impl = expand_enum_from_string(&input)?;
let as_str_impl = expand_as_str_as_ref_str(&input.ident)?;
let display_impl = expand_display_as_ref_str(&input.ident)?;
let debug_impl = expand_debug_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
#as_str_impl
#display_impl
#debug_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()
}
#[doc(hidden)]
#[proc_macro_derive(_FakeDeriveSerde, attributes(serde))]
pub fn fake_derive_serde(_input: TokenStream) -> TokenStream {
TokenStream::new()
}
#[proc_macro_attribute]
pub fn request(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr = parse_macro_input!(attr);
let item = parse_macro_input!(item);
expand_request(attr, item).into()
}
#[proc_macro_attribute]
pub fn response(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr = parse_macro_input!(attr);
let item = parse_macro_input!(item);
expand_response(attr, item).into()
}
#[proc_macro_derive(Request, attributes(ruma_api))]
pub fn derive_request(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input);
expand_derive_request(input).unwrap_or_else(syn::Error::into_compile_error).into()
}
#[proc_macro_derive(Response, attributes(ruma_api))]
pub fn derive_response(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input);
expand_derive_response(input).unwrap_or_else(syn::Error::into_compile_error).into()
}
#[doc(hidden)]
#[proc_macro_derive(_FakeDeriveRumaApi, attributes(ruma_api))]
pub fn fake_derive_ruma_api(_input: TokenStream) -> TokenStream {
TokenStream::new()
}