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]
290pub fn user_id(input: TokenStream) -> TokenStream {
291 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
292 assert!(user_id::validate(&id.value()).is_ok(), "Invalid user_id");
293
294 let output = quote! {
295 <&#dollar_crate::UserId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
296 };
297
298 output.into()
299}
300
301#[proc_macro]
303pub fn base64_public_key(input: TokenStream) -> TokenStream {
304 let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
305 assert!(base64_public_key::validate(&id.value()).is_ok(), "Invalid base64 public key");
306
307 let output = quote! {
308 <&#dollar_crate::DeviceKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
309 };
310
311 output.into()
312}
313
314#[proc_macro_derive(AsRefStr, attributes(ruma_enum))]
316pub fn derive_enum_as_ref_str(input: TokenStream) -> TokenStream {
317 let input = parse_macro_input!(input as ItemEnum);
318 expand_enum_as_ref_str(&input).unwrap_or_else(syn::Error::into_compile_error).into()
319}
320
321#[proc_macro_derive(FromString, attributes(ruma_enum))]
323pub fn derive_enum_from_string(input: TokenStream) -> TokenStream {
324 let input = parse_macro_input!(input as ItemEnum);
325 expand_enum_from_string(&input).unwrap_or_else(syn::Error::into_compile_error).into()
326}
327
328#[proc_macro_derive(AsStrAsRefStr, attributes(ruma_enum))]
333pub fn derive_as_str_as_ref_str(input: TokenStream) -> TokenStream {
334 let input = parse_macro_input!(input as DeriveInput);
335 expand_as_str_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
336}
337
338#[proc_macro_derive(DisplayAsRefStr)]
340pub fn derive_display_as_ref_str(input: TokenStream) -> TokenStream {
341 let input = parse_macro_input!(input as DeriveInput);
342 expand_display_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
343}
344
345#[proc_macro_derive(DebugAsRefStr)]
347pub fn derive_debug_as_ref_str(input: TokenStream) -> TokenStream {
348 let input = parse_macro_input!(input as DeriveInput);
349 expand_debug_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
350}
351
352#[proc_macro_derive(SerializeAsRefStr)]
354pub fn derive_serialize_as_ref_str(input: TokenStream) -> TokenStream {
355 let input = parse_macro_input!(input as DeriveInput);
356 expand_serialize_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
357}
358
359#[proc_macro_derive(DeserializeFromCowStr)]
361pub fn derive_deserialize_from_cow_str(input: TokenStream) -> TokenStream {
362 let input = parse_macro_input!(input as DeriveInput);
363 expand_deserialize_from_cow_str(&input.ident)
364 .unwrap_or_else(syn::Error::into_compile_error)
365 .into()
366}
367
368#[proc_macro_derive(PartialOrdAsRefStr)]
370pub fn derive_partial_ord_as_ref_str(input: TokenStream) -> TokenStream {
371 let input = parse_macro_input!(input as DeriveInput);
372 expand_partial_ord_as_ref_str(&input.ident)
373 .unwrap_or_else(syn::Error::into_compile_error)
374 .into()
375}
376
377#[proc_macro_derive(OrdAsRefStr)]
379pub fn derive_ord_as_ref_str(input: TokenStream) -> TokenStream {
380 let input = parse_macro_input!(input as DeriveInput);
381 expand_ord_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
382}
383
384#[proc_macro_derive(PartialEqAsRefStr)]
386pub fn derive_partial_eq_as_ref_str(input: TokenStream) -> TokenStream {
387 let input = parse_macro_input!(input as DeriveInput);
388 expand_partial_eq_as_ref_str(&input.ident).unwrap_or_else(syn::Error::into_compile_error).into()
389}
390
391#[proc_macro_derive(StringEnum, attributes(ruma_enum))]
394pub fn derive_string_enum(input: TokenStream) -> TokenStream {
395 fn expand_all(input: ItemEnum) -> syn::Result<proc_macro2::TokenStream> {
396 let as_ref_str_impl = expand_enum_as_ref_str(&input)?;
397 let from_string_impl = expand_enum_from_string(&input)?;
398 let as_str_impl = expand_as_str_as_ref_str(&input.ident)?;
399 let display_impl = expand_display_as_ref_str(&input.ident)?;
400 let debug_impl = expand_debug_as_ref_str(&input.ident)?;
401 let serialize_impl = expand_serialize_as_ref_str(&input.ident)?;
402 let deserialize_impl = expand_deserialize_from_cow_str(&input.ident)?;
403
404 Ok(quote! {
405 #as_ref_str_impl
406 #from_string_impl
407 #as_str_impl
408 #display_impl
409 #debug_impl
410 #serialize_impl
411 #deserialize_impl
412 })
413 }
414
415 let input = parse_macro_input!(input as ItemEnum);
416 expand_all(input).unwrap_or_else(syn::Error::into_compile_error).into()
417}
418
419#[doc(hidden)]
423#[proc_macro_derive(_FakeDeriveSerde, attributes(serde))]
424pub fn fake_derive_serde(_input: TokenStream) -> TokenStream {
425 TokenStream::new()
426}
427
428#[proc_macro_attribute]
431pub fn request(attr: TokenStream, item: TokenStream) -> TokenStream {
432 let attr = parse_macro_input!(attr);
433 let item = parse_macro_input!(item);
434 expand_request(attr, item).into()
435}
436
437#[proc_macro_attribute]
440pub fn response(attr: TokenStream, item: TokenStream) -> TokenStream {
441 let attr = parse_macro_input!(attr);
442 let item = parse_macro_input!(item);
443 expand_response(attr, item).into()
444}
445
446#[proc_macro_derive(Request, attributes(ruma_api))]
448pub fn derive_request(input: TokenStream) -> TokenStream {
449 let input = parse_macro_input!(input);
450 expand_derive_request(input).unwrap_or_else(syn::Error::into_compile_error).into()
451}
452
453#[proc_macro_derive(Response, attributes(ruma_api))]
455pub fn derive_response(input: TokenStream) -> TokenStream {
456 let input = parse_macro_input!(input);
457 expand_derive_response(input).unwrap_or_else(syn::Error::into_compile_error).into()
458}
459
460#[doc(hidden)]
464#[proc_macro_derive(_FakeDeriveRumaApi, attributes(ruma_api))]
465pub fn fake_derive_ruma_api(_input: TokenStream) -> TokenStream {
466 TokenStream::new()
467}