1#![doc(html_favicon_url = "https://ruma.dev/favicon.ico")]
2#![doc(html_logo_url = "https://ruma.dev/images/logo.png")]
3#![cfg_attr(feature = "__internal_macro_expand", feature(proc_macro_expand))]
8#![warn(missing_docs)]
9#![allow(unreachable_pub)]
10#![allow(clippy::derive_partial_eq_without_eq)]
12
13use identifiers::expand_id_zst;
14use proc_macro::TokenStream;
15use proc_macro2 as pm2;
16use quote::quote;
17use ruma_identifiers_validation::{
18 base64_public_key, event_id, mxc_uri, room_alias_id, room_id, room_version_id, server_name,
19 server_signing_key_version, user_id,
20};
21use syn::{parse_macro_input, DeriveInput, ItemEnum, ItemStruct};
22
23mod api;
24mod events;
25mod identifiers;
26mod serde;
27mod util;
28
29use self::{
30 api::{
31 request::{expand_derive_request, expand_request},
32 response::{expand_derive_response, expand_response},
33 },
34 events::{
35 event::expand_event,
36 event_content::expand_event_content,
37 event_enum::{expand_event_enums, expand_from_impls_derived},
38 event_parse::EventEnumInput,
39 event_type::expand_event_type_enum,
40 },
41 identifiers::IdentifierInput,
42 serde::{
43 as_str_as_ref_str::expand_as_str_as_ref_str,
44 debug_as_ref_str::expand_debug_as_ref_str,
45 deserialize_from_cow_str::expand_deserialize_from_cow_str,
46 display_as_ref_str::expand_display_as_ref_str,
47 enum_as_ref_str::expand_enum_as_ref_str,
48 enum_from_string::expand_enum_from_string,
49 eq_as_ref_str::expand_partial_eq_as_ref_str,
50 ord_as_ref_str::{expand_ord_as_ref_str, expand_partial_ord_as_ref_str},
51 serialize_as_ref_str::expand_serialize_as_ref_str,
52 },
53 util::{import_ruma_common, import_ruma_events},
54};
55
56#[proc_macro]
89pub fn event_enum(input: TokenStream) -> TokenStream {
90 let event_enum_input = syn::parse_macro_input!(input as EventEnumInput);
91
92 let ruma_common = import_ruma_common();
93
94 let enums = event_enum_input
95 .enums
96 .iter()
97 .map(|e| expand_event_enums(e).unwrap_or_else(syn::Error::into_compile_error))
98 .collect::<pm2::TokenStream>();
99
100 let event_types = expand_event_type_enum(event_enum_input, ruma_common)
101 .unwrap_or_else(syn::Error::into_compile_error);
102
103 let tokens = quote! {
104 #enums
105 #event_types
106 };
107
108 tokens.into()
109}
110
111#[proc_macro_derive(EventContent, attributes(ruma_event))]
133pub fn derive_event_content(input: TokenStream) -> TokenStream {
134 let ruma_events = import_ruma_events();
135 let input = parse_macro_input!(input as DeriveInput);
136
137 expand_event_content(&input, &ruma_events).unwrap_or_else(syn::Error::into_compile_error).into()
138}
139
140#[proc_macro_derive(Event, attributes(ruma_event))]
142pub fn derive_event(input: TokenStream) -> TokenStream {
143 let input = parse_macro_input!(input as DeriveInput);
144 expand_event(input).unwrap_or_else(syn::Error::into_compile_error).into()
145}
146
147#[proc_macro_derive(EventEnumFromEvent)]
149pub fn derive_from_event_to_enum(input: TokenStream) -> TokenStream {
150 let input = parse_macro_input!(input as DeriveInput);
151 expand_from_impls_derived(input).into()
152}
153
154#[proc_macro_derive(IdZst, attributes(ruma_id))]
189pub fn derive_id_zst(input: TokenStream) -> TokenStream {
190 let input = parse_macro_input!(input as ItemStruct);
191 expand_id_zst(input).unwrap_or_else(syn::Error::into_compile_error).into()
192}
193
194#[proc_macro]
196pub fn event_id(input: TokenStream) -> TokenStream {
197 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
198 assert!(event_id::validate(&id.value()).is_ok(), "Invalid event id");
199
200 let output = quote! {
201 <&#dollar_crate::EventId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
202 };
203
204 output.into()
205}
206
207#[proc_macro]
209pub fn room_alias_id(input: TokenStream) -> TokenStream {
210 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
211 assert!(room_alias_id::validate(&id.value()).is_ok(), "Invalid room_alias_id");
212
213 let output = quote! {
214 <&#dollar_crate::RoomAliasId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
215 };
216
217 output.into()
218}
219
220#[proc_macro]
222pub fn room_id(input: TokenStream) -> TokenStream {
223 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
224 assert!(room_id::validate(&id.value()).is_ok(), "Invalid room_id");
225
226 let output = quote! {
227 <&#dollar_crate::RoomId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
228 };
229
230 output.into()
231}
232
233#[proc_macro]
235pub fn room_version_id(input: TokenStream) -> TokenStream {
236 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
237 assert!(room_version_id::validate(&id.value()).is_ok(), "Invalid room_version_id");
238
239 let output = quote! {
240 <#dollar_crate::RoomVersionId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
241 };
242
243 output.into()
244}
245
246#[proc_macro]
248pub fn server_signing_key_version(input: TokenStream) -> TokenStream {
249 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
250 assert!(
251 server_signing_key_version::validate(&id.value()).is_ok(),
252 "Invalid server_signing_key_version"
253 );
254
255 let output = quote! {
256 <&#dollar_crate::ServerSigningKeyVersion as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
257 };
258
259 output.into()
260}
261
262#[proc_macro]
264pub fn server_name(input: TokenStream) -> TokenStream {
265 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
266 assert!(server_name::validate(&id.value()).is_ok(), "Invalid server_name");
267
268 let output = quote! {
269 <&#dollar_crate::ServerName as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
270 };
271
272 output.into()
273}
274
275#[proc_macro]
277pub fn mxc_uri(input: TokenStream) -> TokenStream {
278 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
279 assert!(mxc_uri::validate(&id.value()).is_ok(), "Invalid mxc://");
280
281 let output = quote! {
282 <&#dollar_crate::MxcUri as ::std::convert::From<&str>>::from(#id)
283 };
284
285 output.into()
286}
287
288#[proc_macro]
292pub fn user_id(input: TokenStream) -> TokenStream {
293 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
294 assert!(user_id::validate_strict(&id.value()).is_ok(), "Invalid user_id");
295
296 let output = quote! {
297 <&#dollar_crate::UserId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
298 };
299
300 output.into()
301}
302
303#[proc_macro]
305pub fn base64_public_key(input: TokenStream) -> TokenStream {
306 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
307 assert!(base64_public_key::validate(&id.value()).is_ok(), "Invalid base64 public key");
308
309 let output = quote! {
310 <&#dollar_crate::DeviceKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
311 };
312
313 output.into()
314}
315
316#[proc_macro_derive(AsRefStr, attributes(ruma_enum))]
318pub fn derive_enum_as_ref_str(input: TokenStream) -> TokenStream {
319 let input = parse_macro_input!(input as ItemEnum);
320 expand_enum_as_ref_str(&input).unwrap_or_else(syn::Error::into_compile_error).into()
321}
322
323#[proc_macro_derive(FromString, attributes(ruma_enum))]
325pub fn derive_enum_from_string(input: TokenStream) -> TokenStream {
326 let input = parse_macro_input!(input as ItemEnum);
327 expand_enum_from_string(&input).unwrap_or_else(syn::Error::into_compile_error).into()
328}
329
330#[proc_macro_derive(AsStrAsRefStr, attributes(ruma_enum))]
335pub fn derive_as_str_as_ref_str(input: TokenStream) -> TokenStream {
336 let input = parse_macro_input!(input as DeriveInput);
337 expand_as_str_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
338}
339
340#[proc_macro_derive(DisplayAsRefStr)]
342pub fn derive_display_as_ref_str(input: TokenStream) -> TokenStream {
343 let input = parse_macro_input!(input as DeriveInput);
344 expand_display_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
345}
346
347#[proc_macro_derive(DebugAsRefStr)]
349pub fn derive_debug_as_ref_str(input: TokenStream) -> TokenStream {
350 let input = parse_macro_input!(input as DeriveInput);
351 expand_debug_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
352}
353
354#[proc_macro_derive(SerializeAsRefStr)]
356pub fn derive_serialize_as_ref_str(input: TokenStream) -> TokenStream {
357 let input = parse_macro_input!(input as DeriveInput);
358 expand_serialize_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
359}
360
361#[proc_macro_derive(DeserializeFromCowStr)]
363pub fn derive_deserialize_from_cow_str(input: TokenStream) -> TokenStream {
364 let input = parse_macro_input!(input as DeriveInput);
365 expand_deserialize_from_cow_str(&input.ident)
366 .unwrap_or_else(syn::Error::into_compile_error)
367 .into()
368}
369
370#[proc_macro_derive(PartialOrdAsRefStr)]
372pub fn derive_partial_ord_as_ref_str(input: TokenStream) -> TokenStream {
373 let input = parse_macro_input!(input as DeriveInput);
374 expand_partial_ord_as_ref_str(&input.ident)
375 .unwrap_or_else(syn::Error::into_compile_error)
376 .into()
377}
378
379#[proc_macro_derive(OrdAsRefStr)]
381pub fn derive_ord_as_ref_str(input: TokenStream) -> TokenStream {
382 let input = parse_macro_input!(input as DeriveInput);
383 expand_ord_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
384}
385
386#[proc_macro_derive(PartialEqAsRefStr)]
388pub fn derive_partial_eq_as_ref_str(input: TokenStream) -> TokenStream {
389 let input = parse_macro_input!(input as DeriveInput);
390 expand_partial_eq_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
391}
392
393#[proc_macro_derive(StringEnum, attributes(ruma_enum))]
396pub fn derive_string_enum(input: TokenStream) -> TokenStream {
397 fn expand_all(input: ItemEnum) -> syn::Result<proc_macro2::TokenStream> {
398 let as_ref_str_impl = expand_enum_as_ref_str(&input)?;
399 let from_string_impl = expand_enum_from_string(&input)?;
400 let as_str_impl = expand_as_str_as_ref_str(&input.ident)?;
401 let display_impl = expand_display_as_ref_str(&input.ident)?;
402 let debug_impl = expand_debug_as_ref_str(&input.ident)?;
403 let serialize_impl = expand_serialize_as_ref_str(&input.ident)?;
404 let deserialize_impl = expand_deserialize_from_cow_str(&input.ident)?;
405
406 Ok(quote! {
407 #as_ref_str_impl
408 #from_string_impl
409 #as_str_impl
410 #display_impl
411 #debug_impl
412 #serialize_impl
413 #deserialize_impl
414 })
415 }
416
417 let input = parse_macro_input!(input as ItemEnum);
418 expand_all(input).unwrap_or_else(syn::Error::into_compile_error).into()
419}
420
421#[doc(hidden)]
425#[proc_macro_derive(_FakeDeriveSerde, attributes(serde))]
426pub fn fake_derive_serde(_input: TokenStream) -> TokenStream {
427 TokenStream::new()
428}
429
430#[proc_macro_attribute]
433pub fn request(attr: TokenStream, item: TokenStream) -> TokenStream {
434 let attr = parse_macro_input!(attr);
435 let item = parse_macro_input!(item);
436 expand_request(attr, item).into()
437}
438
439#[proc_macro_attribute]
442pub fn response(attr: TokenStream, item: TokenStream) -> TokenStream {
443 let attr = parse_macro_input!(attr);
444 let item = parse_macro_input!(item);
445 expand_response(attr, item).into()
446}
447
448#[proc_macro_derive(Request, attributes(ruma_api))]
450pub fn derive_request(input: TokenStream) -> TokenStream {
451 let input = parse_macro_input!(input);
452 expand_derive_request(input).unwrap_or_else(syn::Error::into_compile_error).into()
453}
454
455#[proc_macro_derive(Response, attributes(ruma_api))]
457pub fn derive_response(input: TokenStream) -> TokenStream {
458 let input = parse_macro_input!(input);
459 expand_derive_response(input).unwrap_or_else(syn::Error::into_compile_error).into()
460}
461
462#[doc(hidden)]
466#[proc_macro_derive(_FakeDeriveRumaApi, attributes(ruma_api))]
467pub fn fake_derive_ruma_api(_input: TokenStream) -> TokenStream {
468 TokenStream::new()
469}