1use std::fmt;
4
5use proc_macro2::{Span, TokenStream};
6use quote::{format_ident, quote, IdentFragment, ToTokens};
7use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr};
8
9use super::event_parse::{EventEnumDecl, EventEnumEntry, EventKind};
10use crate::util::m_prefix_name_to_type_name;
11
12mod kw {
14 syn::custom_keyword!(kind);
15 syn::custom_keyword!(events);
16}
17
18pub(crate) fn is_non_stripped_room_event(kind: EventKind, var: EventEnumVariation) -> bool {
19 matches!(kind, EventKind::MessageLike | EventKind::State)
20 && matches!(var, EventEnumVariation::None | EventEnumVariation::Sync)
21}
22
23type EventKindFn = fn(EventKind, EventEnumVariation) -> bool;
24
25const EVENT_FIELDS: &[(&str, EventKindFn)] = &[
30 ("origin_server_ts", is_non_stripped_room_event),
31 ("room_id", |kind, var| {
32 matches!(kind, EventKind::MessageLike | EventKind::State | EventKind::Ephemeral)
33 && matches!(var, EventEnumVariation::None)
34 }),
35 ("event_id", is_non_stripped_room_event),
36 ("sender", |kind, var| {
37 matches!(kind, EventKind::MessageLike | EventKind::State | EventKind::ToDevice)
38 && var != EventEnumVariation::Initial
39 }),
40];
41
42pub fn expand_event_enums(input: &EventEnumDecl) -> syn::Result<TokenStream> {
44 use EventEnumVariation as V;
45
46 let ruma_events = crate::import_ruma_events();
47
48 let mut res = TokenStream::new();
49
50 let kind = input.kind;
51 let attrs = &input.attrs;
52 let docs: Vec<_> = input.events.iter().map(EventEnumEntry::docs).collect::<syn::Result<_>>()?;
53 let variants: Vec<_> =
54 input.events.iter().map(EventEnumEntry::to_variant).collect::<syn::Result<_>>()?;
55
56 let events = &input.events;
57 let docs = &docs;
58 let variants = &variants;
59 let ruma_events = &ruma_events;
60
61 res.extend(expand_content_enum(kind, events, docs, attrs, variants, ruma_events));
62 res.extend(
63 expand_event_enum(kind, V::None, events, docs, attrs, variants, ruma_events)
64 .unwrap_or_else(syn::Error::into_compile_error),
65 );
66
67 if matches!(kind, EventKind::MessageLike | EventKind::State) {
68 res.extend(
69 expand_event_enum(kind, V::Sync, events, docs, attrs, variants, ruma_events)
70 .unwrap_or_else(syn::Error::into_compile_error),
71 );
72 res.extend(
73 expand_from_full_event(kind, V::None, variants)
74 .unwrap_or_else(syn::Error::into_compile_error),
75 );
76 res.extend(
77 expand_into_full_event(kind, V::Sync, variants, ruma_events)
78 .unwrap_or_else(syn::Error::into_compile_error),
79 );
80 }
81
82 if matches!(kind, EventKind::Ephemeral) {
83 res.extend(
84 expand_event_enum(kind, V::Sync, events, docs, attrs, variants, ruma_events)
85 .unwrap_or_else(syn::Error::into_compile_error),
86 );
87 }
88
89 if matches!(kind, EventKind::State) {
90 res.extend(expand_full_content_enum(kind, events, docs, attrs, variants, ruma_events));
91 res.extend(
92 expand_event_enum(kind, V::Stripped, events, docs, attrs, variants, ruma_events)
93 .unwrap_or_else(syn::Error::into_compile_error),
94 );
95 res.extend(
96 expand_event_enum(kind, V::Initial, events, docs, attrs, variants, ruma_events)
97 .unwrap_or_else(syn::Error::into_compile_error),
98 );
99 }
100
101 Ok(res)
102}
103
104fn expand_event_enum(
105 kind: EventKind,
106 var: EventEnumVariation,
107 events: &[EventEnumEntry],
108 docs: &[TokenStream],
109 attrs: &[Attribute],
110 variants: &[EventEnumVariant],
111 ruma_events: &TokenStream,
112) -> syn::Result<TokenStream> {
113 let event_struct = kind.to_event_ident(var.into())?;
114 let ident = kind.to_event_enum_ident(var.into())?;
115
116 let variant_decls = variants.iter().map(|v| v.decl());
117 let event_ty: Vec<_> = events.iter().map(|event| event.to_event_path(kind, var)).collect();
118
119 let custom_content_ty = format_ident!("Custom{}Content", kind);
120
121 let deserialize_impl = expand_deserialize_impl(kind, var, events, ruma_events)?;
122 let field_accessor_impl =
123 expand_accessor_methods(kind, var, variants, &event_struct, ruma_events)?;
124 let from_impl = expand_from_impl(&ident, &event_ty, variants);
125
126 Ok(quote! {
127 #( #attrs )*
128 #[derive(Clone, Debug)]
129 #[allow(clippy::large_enum_variant, unused_qualifications)]
130 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
131 pub enum #ident {
132 #(
133 #docs
134 #variant_decls(#event_ty),
135 )*
136 #[doc(hidden)]
138 _Custom(
139 #ruma_events::#event_struct<
140 #ruma_events::_custom::#custom_content_ty
141 >,
142 ),
143 }
144
145 #deserialize_impl
146 #field_accessor_impl
147 #from_impl
148 })
149}
150
151fn expand_deserialize_impl(
152 kind: EventKind,
153 var: EventEnumVariation,
154 events: &[EventEnumEntry],
155 ruma_events: &TokenStream,
156) -> syn::Result<TokenStream> {
157 let ruma_common = quote! { #ruma_events::exports::ruma_common };
158 let serde = quote! { #ruma_events::exports::serde };
159 let serde_json = quote! { #ruma_events::exports::serde_json };
160
161 let ident = kind.to_event_enum_ident(var.into())?;
162
163 let match_arms: TokenStream = events
164 .iter()
165 .map(|event| {
166 let variant = event.to_variant()?;
167 let variant_attrs = {
168 let attrs = &variant.attrs;
169 quote! { #(#attrs)* }
170 };
171 let self_variant = variant.ctor(quote! { Self });
172 let content = event.to_event_path(kind, var);
173 let ev_types = event.aliases.iter().chain([&event.ev_type]).map(|ev_type| {
174 if event.has_type_fragment() {
175 let ev_type = ev_type.value();
176 let prefix = ev_type
177 .strip_suffix('*')
178 .expect("event type with type fragment must end with *");
179 quote! { t if t.starts_with(#prefix) }
180 } else {
181 quote! { #ev_type }
182 }
183 });
184
185 Ok(quote! {
186 #variant_attrs #(#ev_types)|* => {
187 let event = #serde_json::from_str::<#content>(json.get())
188 .map_err(D::Error::custom)?;
189 Ok(#self_variant(event))
190 },
191 })
192 })
193 .collect::<syn::Result<_>>()?;
194
195 Ok(quote! {
196 #[allow(unused_qualifications)]
197 impl<'de> #serde::de::Deserialize<'de> for #ident {
198 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
199 where
200 D: #serde::de::Deserializer<'de>,
201 {
202 use #serde::de::Error as _;
203
204 let json = Box::<#serde_json::value::RawValue>::deserialize(deserializer)?;
205 let #ruma_events::EventTypeDeHelper { ev_type, .. } =
206 #ruma_common::serde::from_raw_json_value(&json)?;
207
208 match &*ev_type {
209 #match_arms
210 _ => {
211 let event = #serde_json::from_str(json.get()).map_err(D::Error::custom)?;
212 Ok(Self::_Custom(event))
213 },
214 }
215 }
216 }
217 })
218}
219
220fn expand_from_impl(
221 ty: &Ident,
222 event_ty: &[TokenStream],
223 variants: &[EventEnumVariant],
224) -> TokenStream {
225 let from_impls = event_ty.iter().zip(variants).map(|(event_ty, variant)| {
226 let ident = &variant.ident;
227 let attrs = &variant.attrs;
228
229 quote! {
230 #[allow(unused_qualifications)]
231 #[automatically_derived]
232 #(#attrs)*
233 impl ::std::convert::From<#event_ty> for #ty {
234 fn from(c: #event_ty) -> Self {
235 Self::#ident(c)
236 }
237 }
238 }
239 });
240
241 quote! { #( #from_impls )* }
242}
243
244fn expand_from_full_event(
245 kind: EventKind,
246 var: EventEnumVariation,
247 variants: &[EventEnumVariant],
248) -> syn::Result<TokenStream> {
249 let ident = kind.to_event_enum_ident(var.into())?;
250 let sync = kind.to_event_enum_ident(var.to_sync().into())?;
251
252 let ident_variants = variants.iter().map(|v| v.match_arm(&ident));
253 let self_variants = variants.iter().map(|v| v.ctor(quote! { Self }));
254
255 Ok(quote! {
256 #[automatically_derived]
257 impl ::std::convert::From<#ident> for #sync {
258 fn from(event: #ident) -> Self {
259 match event {
260 #(
261 #ident_variants(event) => {
262 #self_variants(::std::convert::From::from(event))
263 },
264 )*
265 #ident::_Custom(event) => {
266 Self::_Custom(::std::convert::From::from(event))
267 },
268 }
269 }
270 }
271 })
272}
273
274fn expand_into_full_event(
275 kind: EventKind,
276 var: EventEnumVariation,
277 variants: &[EventEnumVariant],
278 ruma_events: &TokenStream,
279) -> syn::Result<TokenStream> {
280 let ruma_common = quote! { #ruma_events::exports::ruma_common };
281
282 let ident = kind.to_event_enum_ident(var.into())?;
283 let full = kind.to_event_enum_ident(var.to_full().into())?;
284
285 let self_variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
286 let full_variants = variants.iter().map(|v| v.ctor(&full));
287
288 Ok(quote! {
289 #[automatically_derived]
290 impl #ident {
291 pub fn into_full_event(self, room_id: #ruma_common::OwnedRoomId) -> #full {
293 match self {
294 #(
295 #self_variants(event) => {
296 #full_variants(event.into_full_event(room_id))
297 },
298 )*
299 Self::_Custom(event) => {
300 #full::_Custom(event.into_full_event(room_id))
301 },
302 }
303 }
304 }
305 })
306}
307
308fn expand_content_enum(
310 kind: EventKind,
311 events: &[EventEnumEntry],
312 docs: &[TokenStream],
313 attrs: &[Attribute],
314 variants: &[EventEnumVariant],
315 ruma_events: &TokenStream,
316) -> syn::Result<TokenStream> {
317 let serde = quote! { #ruma_events::exports::serde };
318
319 let ident = kind.to_content_enum();
320
321 let event_type_enum = kind.to_event_type_enum();
322
323 let content: Vec<_> =
324 events.iter().map(|event| event.to_event_content_path(kind, None)).collect();
325
326 let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>();
327 let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::<Vec<_>>();
328
329 let sub_trait_name = format_ident!("{kind}Content");
330 let state_event_content_impl = (kind == EventKind::State).then(|| {
331 quote! {
332 type StateKey = String;
333 }
334 });
335
336 let from_impl = expand_from_impl(&ident, &content, variants);
337
338 let serialize_custom_event_error_path =
339 quote! { #ruma_events::serialize_custom_event_error }.to_string();
340
341 let serde_json = quote! { #ruma_events::exports::serde_json };
343 let event_type_match_arms: TokenStream = events
344 .iter()
345 .map(|event| {
346 let variant = event.to_variant()?;
347 let variant_attrs = {
348 let attrs = &variant.attrs;
349 quote! { #(#attrs)* }
350 };
351 let self_variant = variant.ctor(quote! { Self });
352
353 let ev_types = event.aliases.iter().chain([&event.ev_type]).map(|ev_type| {
354 if event.has_type_fragment() {
355 let ev_type = ev_type.value();
356 let prefix = ev_type
357 .strip_suffix('*')
358 .expect("event type with type fragment must end with *");
359 quote! { t if t.starts_with(#prefix) }
360 } else {
361 quote! { #ev_type }
362 }
363 });
364
365 let deserialize_content = if event.has_type_fragment() {
366 let content_type = event.to_event_content_path(kind, None);
370 quote! {
371 #content_type::from_parts(event_type, json)?
372 }
373 } else {
374 quote! {
377 #serde_json::from_str(json.get())?
378 }
379 };
380
381 Ok(quote! {
382 #variant_attrs #(#ev_types)|* => {
383 let content = #deserialize_content;
384 Ok(#self_variant(content))
385 },
386 })
387 })
388 .collect::<syn::Result<_>>()?;
389
390 Ok(quote! {
391 #( #attrs )*
392 #[derive(Clone, Debug, #serde::Serialize)]
393 #[serde(untagged)]
394 #[allow(clippy::large_enum_variant)]
395 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
396 pub enum #ident {
397 #(
398 #docs
399 #variant_decls(#content),
400 )*
401 #[doc(hidden)]
402 #[serde(serialize_with = #serialize_custom_event_error_path)]
403 _Custom {
404 event_type: crate::PrivOwnedStr,
405 },
406 }
407
408 #[automatically_derived]
409 impl #ruma_events::EventContent for #ident {
410 type EventType = #ruma_events::#event_type_enum;
411
412 fn event_type(&self) -> Self::EventType {
413 match self {
414 #( #variant_arms(content) => content.event_type(), )*
415 Self::_Custom { event_type } => ::std::convert::From::from(&event_type.0[..]),
416 }
417 }
418 }
419
420 #[automatically_derived]
421 impl #ruma_events::EventContentFromType for #ident {
422 fn from_parts(event_type: &str, json: &#serde_json::value::RawValue) -> serde_json::Result<Self> {
423 match event_type {
424 #event_type_match_arms
425
426 _ => {
427 Ok(Self::_Custom {
428 event_type: crate::PrivOwnedStr(
429 ::std::convert::From::from(event_type.to_owned())
430 )
431 })
432 }
433 }
434 }
435 }
436
437 #[automatically_derived]
438 impl #ruma_events::#sub_trait_name for #ident {
439 #state_event_content_impl
440 }
441
442 #from_impl
443 })
444}
445
446fn expand_full_content_enum(
448 kind: EventKind,
449 events: &[EventEnumEntry],
450 docs: &[TokenStream],
451 attrs: &[Attribute],
452 variants: &[EventEnumVariant],
453 ruma_events: &TokenStream,
454) -> syn::Result<TokenStream> {
455 let ident = kind.to_full_content_enum();
456
457 let event_type_enum = kind.to_event_type_enum();
458
459 let content: Vec<_> =
460 events.iter().map(|event| event.to_event_content_path(kind, None)).collect();
461
462 let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>();
463 let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::<Vec<_>>();
464
465 Ok(quote! {
466 #( #attrs )*
467 #[derive(Clone, Debug)]
468 #[allow(clippy::large_enum_variant)]
469 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
470 pub enum #ident {
471 #(
472 #docs
473 #variant_decls(#ruma_events::FullStateEventContent<#content>),
474 )*
475 #[doc(hidden)]
476 _Custom {
477 event_type: crate::PrivOwnedStr,
478 redacted: bool,
479 },
480 }
481
482 impl #ident {
483 pub fn event_type(&self) -> #ruma_events::#event_type_enum {
485 match self {
486 #( #variant_arms(content) => content.event_type(), )*
487 Self::_Custom { event_type, .. } => ::std::convert::From::from(&event_type.0[..]),
488 }
489 }
490 }
491 })
492}
493
494fn expand_accessor_methods(
495 kind: EventKind,
496 var: EventEnumVariation,
497 variants: &[EventEnumVariant],
498 event_struct: &Ident,
499 ruma_events: &TokenStream,
500) -> syn::Result<TokenStream> {
501 let ruma_common = quote! { #ruma_events::exports::ruma_common };
502
503 let ident = kind.to_event_enum_ident(var.into())?;
504 let event_type_enum = format_ident!("{}Type", kind);
505 let self_variants: Vec<_> = variants.iter().map(|v| v.match_arm(quote! { Self })).collect();
506
507 let maybe_redacted =
508 kind.is_timeline() && matches!(var, EventEnumVariation::None | EventEnumVariation::Sync);
509
510 let event_type_match_arms = if maybe_redacted {
511 quote! {
512 #( #self_variants(event) => event.event_type(), )*
513 Self::_Custom(event) => event.event_type(),
514 }
515 } else {
516 quote! {
517 #( #self_variants(event) =>
518 #ruma_events::EventContent::event_type(&event.content), )*
519 Self::_Custom(event) => ::std::convert::From::from(
520 #ruma_events::EventContent::event_type(&event.content),
521 ),
522 }
523 };
524
525 let content_enum = kind.to_content_enum();
526 let content_variants: Vec<_> = variants.iter().map(|v| v.ctor(&content_enum)).collect();
527 let content_accessor = if maybe_redacted {
528 let mut accessors = quote! {
529 pub fn original_content(&self) -> Option<#content_enum> {
531 match self {
532 #(
533 #self_variants(event) => {
534 event.as_original().map(|ev| #content_variants(ev.content.clone()))
535 }
536 )*
537 Self::_Custom(event) => event.as_original().map(|ev| {
538 #content_enum::_Custom {
539 event_type: crate::PrivOwnedStr(
540 ::std::convert::From::from(
541 ::std::string::ToString::to_string(
542 &#ruma_events::EventContent::event_type(
543 &ev.content,
544 ),
545 ),
546 ),
547 ),
548 }
549 }),
550 }
551 }
552
553 pub fn is_redacted(&self) -> bool {
555 match self {
556 #(
557 #self_variants(event) => {
558 event.as_original().is_none()
559 }
560 )*
561 Self::_Custom(event) => event.as_original().is_none(),
562 }
563 }
564 };
565
566 if kind == EventKind::State {
567 let full_content_enum = kind.to_full_content_enum();
568 let full_content_variants: Vec<_> =
569 variants.iter().map(|v| v.ctor(&full_content_enum)).collect();
570
571 accessors = quote! {
572 #accessors
573
574 pub fn content(&self) -> #full_content_enum {
576 match self {
577 #(
578 #self_variants(event) => match event {
579 #ruma_events::#event_struct::Original(ev) => #full_content_variants(
580 #ruma_events::FullStateEventContent::Original {
581 content: ev.content.clone(),
582 prev_content: ev.unsigned.prev_content.clone()
583 }
584 ),
585 #ruma_events::#event_struct::Redacted(ev) => #full_content_variants(
586 #ruma_events::FullStateEventContent::Redacted(
587 ev.content.clone()
588 )
589 ),
590 }
591 )*
592 Self::_Custom(event) => match event {
593 #ruma_events::#event_struct::Original(ev) => {
594 #full_content_enum::_Custom {
595 event_type: crate::PrivOwnedStr(
596 ::std::string::ToString::to_string(
597 &#ruma_events::EventContent::event_type(
598 &ev.content,
599 ),
600 ).into_boxed_str(),
601 ),
602 redacted: false,
603 }
604 }
605 #ruma_events::#event_struct::Redacted(ev) => {
606 #full_content_enum::_Custom {
607 event_type: crate::PrivOwnedStr(
608 ::std::string::ToString::to_string(
609 &#ruma_events::EventContent::event_type(
610 &ev.content,
611 ),
612 ).into_boxed_str(),
613 ),
614 redacted: true,
615 }
616 }
617 },
618 }
619 }
620 };
621 }
622
623 accessors
624 } else if var == EventEnumVariation::Stripped {
625 TokenStream::new()
627 } else {
628 quote! {
629 pub fn content(&self) -> #content_enum {
631 match self {
632 #( #self_variants(event) => #content_variants(event.content.clone()), )*
633 Self::_Custom(event) => #content_enum::_Custom {
634 event_type: crate::PrivOwnedStr(
635 ::std::convert::From::from(
636 ::std::string::ToString::to_string(
637 &#ruma_events::EventContent::event_type(&event.content)
638 )
639 ),
640 ),
641 },
642 }
643 }
644 }
645 };
646
647 let methods = EVENT_FIELDS.iter().map(|(name, has_field)| {
648 has_field(kind, var).then(|| {
649 let docs = format!("Returns this event's `{name}` field.");
650 let ident = Ident::new(name, Span::call_site());
651 let field_type = field_return_type(name, ruma_events);
652 let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
653 let call_parens = maybe_redacted.then(|| quote! { () });
654 let ampersand = (*name != "origin_server_ts").then(|| quote! { & });
655
656 quote! {
657 #[doc = #docs]
658 pub fn #ident(&self) -> #field_type {
659 match self {
660 #( #variants(event) => #ampersand event.#ident #call_parens, )*
661 Self::_Custom(event) => #ampersand event.#ident #call_parens,
662 }
663 }
664 }
665 })
666 });
667
668 let state_key_accessor = (kind == EventKind::State).then(|| {
669 let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
670 let call_parens = maybe_redacted.then(|| quote! { () });
671
672 quote! {
673 pub fn state_key(&self) -> &::std::primitive::str {
675 match self {
676 #( #variants(event) => &event.state_key #call_parens .as_ref(), )*
677 Self::_Custom(event) => &event.state_key #call_parens .as_ref(),
678 }
679 }
680 }
681 });
682
683 let relations_accessor = (kind == EventKind::MessageLike).then(|| {
684 let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
685
686 quote! {
687 pub fn relations(
689 &self,
690 ) -> #ruma_events::BundledMessageLikeRelations<AnySyncMessageLikeEvent> {
691 match self {
692 #(
693 #variants(event) => event.as_original().map_or_else(
694 ::std::default::Default::default,
695 |ev| ev.unsigned.relations.clone().map_replace(|r| {
696 ::std::convert::From::from(r.into_maybe_redacted())
697 }),
698 ),
699 )*
700 Self::_Custom(event) => event.as_original().map_or_else(
701 ::std::default::Default::default,
702 |ev| ev.unsigned.relations.clone().map_replace(|r| {
703 AnySyncMessageLikeEvent::_Custom(r.into_maybe_redacted())
704 }),
705 ),
706 }
707 }
708 }
709 });
710
711 let maybe_redacted_accessors = maybe_redacted.then(|| {
712 let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
713
714 quote! {
715 pub fn transaction_id(&self) -> Option<&#ruma_common::TransactionId> {
717 match self {
718 #(
719 #variants(event) => {
720 event.as_original().and_then(|ev| ev.unsigned.transaction_id.as_deref())
721 }
722 )*
723 Self::_Custom(event) => {
724 event.as_original().and_then(|ev| ev.unsigned.transaction_id.as_deref())
725 }
726 }
727 }
728 }
729 });
730
731 Ok(quote! {
732 #[automatically_derived]
733 impl #ident {
734 pub fn event_type(&self) -> #ruma_events::#event_type_enum {
736 match self { #event_type_match_arms }
737 }
738
739 #content_accessor
740 #( #methods )*
741 #relations_accessor
742 #state_key_accessor
743 #maybe_redacted_accessors
744 }
745 })
746}
747
748fn field_return_type(name: &str, ruma_events: &TokenStream) -> TokenStream {
749 let ruma_common = quote! { #ruma_events::exports::ruma_common };
750 match name {
751 "origin_server_ts" => quote! { #ruma_common::MilliSecondsSinceUnixEpoch },
752 "room_id" => quote! { &#ruma_common::RoomId },
753 "event_id" => quote! { &#ruma_common::EventId },
754 "sender" => quote! { &#ruma_common::UserId },
755 _ => panic!("the `ruma_macros::event_enum::EVENT_FIELD` const was changed"),
756 }
757}
758
759pub(crate) struct EventEnumVariant {
760 pub attrs: Vec<Attribute>,
761 pub ident: Ident,
762}
763
764impl EventEnumVariant {
765 pub(crate) fn to_tokens<T>(&self, prefix: Option<T>, with_attrs: bool) -> TokenStream
766 where
767 T: ToTokens,
768 {
769 let mut tokens = TokenStream::new();
770 if with_attrs {
771 for attr in &self.attrs {
772 attr.to_tokens(&mut tokens);
773 }
774 }
775 if let Some(p) = prefix {
776 tokens.extend(quote! { #p :: });
777 }
778 self.ident.to_tokens(&mut tokens);
779
780 tokens
781 }
782
783 pub(crate) fn decl(&self) -> TokenStream {
784 self.to_tokens::<TokenStream>(None, true)
785 }
786
787 pub(crate) fn match_arm(&self, prefix: impl ToTokens) -> TokenStream {
788 self.to_tokens(Some(prefix), true)
789 }
790
791 pub(crate) fn ctor(&self, prefix: impl ToTokens) -> TokenStream {
792 self.to_tokens(Some(prefix), false)
793 }
794}
795
796impl EventEnumEntry {
797 pub(crate) fn has_type_fragment(&self) -> bool {
798 self.ev_type.value().ends_with(".*")
799 }
800
801 pub(crate) fn to_variant(&self) -> syn::Result<EventEnumVariant> {
802 let attrs = self.attrs.clone();
803 let ident = self.ident()?;
804
805 Ok(EventEnumVariant { attrs, ident })
806 }
807
808 pub(crate) fn stable_name(&self) -> syn::Result<&LitStr> {
809 if self.ev_type.value().starts_with("m.") {
810 Ok(&self.ev_type)
811 } else {
812 self.aliases.iter().find(|alias| alias.value().starts_with("m.")).ok_or_else(|| {
813 syn::Error::new(
814 Span::call_site(),
815 format!(
816 "A matrix event must declare a well-known type that starts with `m.` \
817 either as the main type or as an alias, or must declare the ident that \
818 should be used if it is only an unstable type, found main type `{}`",
819 self.ev_type.value()
820 ),
821 )
822 })
823 }
824 }
825
826 pub(crate) fn ident(&self) -> syn::Result<Ident> {
827 if let Some(ident) = self.ident.clone() {
828 Ok(ident)
829 } else {
830 m_prefix_name_to_type_name(self.stable_name()?)
831 }
832 }
833
834 fn to_event_path(&self, kind: EventKind, var: EventEnumVariation) -> TokenStream {
835 let path = &self.ev_path;
836 let ident = self.ident().unwrap();
837 let event_name = if kind == EventKind::ToDevice {
838 assert_eq!(var, EventEnumVariation::None);
839 format_ident!("ToDevice{ident}Event")
840 } else {
841 format_ident!("{}{ident}Event", var)
842 };
843 quote! { #path::#event_name }
844 }
845
846 fn to_event_content_path(&self, kind: EventKind, prefix: Option<&str>) -> TokenStream {
847 let path = &self.ev_path;
848 let ident = self.ident().unwrap();
849 let content_str = match kind {
850 EventKind::ToDevice => {
851 format_ident!("ToDevice{}{ident}EventContent", prefix.unwrap_or(""))
852 }
853 _ => format_ident!("{}{ident}EventContent", prefix.unwrap_or("")),
854 };
855
856 quote! {
857 #path::#content_str
858 }
859 }
860
861 pub(crate) fn docs(&self) -> syn::Result<TokenStream> {
862 let main_name = self.stable_name().unwrap_or(&self.ev_type);
863
864 let mut doc = quote! {
865 #[doc = #main_name]
866 };
867
868 if self.ev_type != *main_name {
869 let unstable_name =
870 format!("This variant uses the unstable type `{}`.", self.ev_type.value());
871
872 doc.extend(quote! {
873 #[doc = ""]
874 #[doc = #unstable_name]
875 });
876 }
877
878 match self.aliases.len() {
879 0 => {}
880 1 => {
881 let alias = format!(
882 "This variant can also be deserialized from the `{}` type.",
883 self.aliases[0].value()
884 );
885 doc.extend(quote! {
886 #[doc = ""]
887 #[doc = #alias]
888 });
889 }
890 _ => {
891 let aliases = format!(
892 "This variant can also be deserialized from the following types: {}.",
893 self.aliases
894 .iter()
895 .map(|alias| format!("`{}`", alias.value()))
896 .collect::<Vec<_>>()
897 .join(", ")
898 );
899 doc.extend(quote! {
900 #[doc = ""]
901 #[doc = #aliases]
902 });
903 }
904 }
905
906 Ok(doc)
907 }
908}
909
910pub(crate) fn expand_from_impls_derived(input: DeriveInput) -> TokenStream {
911 let variants = match &input.data {
912 Data::Enum(DataEnum { variants, .. }) => variants,
913 _ => panic!("this derive macro only works with enums"),
914 };
915
916 let from_impls = variants.iter().map(|variant| match &variant.fields {
917 syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
918 let inner_struct = &fields.unnamed.first().unwrap().ty;
919 let var_ident = &variant.ident;
920 let id = &input.ident;
921 quote! {
922 #[automatically_derived]
923 impl ::std::convert::From<#inner_struct> for #id {
924 fn from(c: #inner_struct) -> Self {
925 Self::#var_ident(c)
926 }
927 }
928 }
929 }
930 _ => {
931 panic!("this derive macro only works with enum variants with a single unnamed field")
932 }
933 });
934
935 quote! {
936 #( #from_impls )*
937 }
938}
939
940#[derive(Clone, Copy, Debug, Eq, PartialEq)]
942pub enum EventEnumVariation {
943 None,
944 Sync,
945 Stripped,
946 Initial,
947}
948
949impl From<EventEnumVariation> for super::event_parse::EventKindVariation {
950 fn from(v: EventEnumVariation) -> Self {
951 match v {
952 EventEnumVariation::None => Self::None,
953 EventEnumVariation::Sync => Self::Sync,
954 EventEnumVariation::Stripped => Self::Stripped,
955 EventEnumVariation::Initial => Self::Initial,
956 }
957 }
958}
959
960impl EventEnumVariation {
962 pub fn to_sync(self) -> Self {
963 match self {
964 EventEnumVariation::None => EventEnumVariation::Sync,
965 _ => panic!("No sync form of {self:?}"),
966 }
967 }
968
969 pub fn to_full(self) -> Self {
970 match self {
971 EventEnumVariation::Sync => EventEnumVariation::None,
972 _ => panic!("No full form of {self:?}"),
973 }
974 }
975}
976
977impl IdentFragment for EventEnumVariation {
978 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
979 match self {
980 EventEnumVariation::None => write!(f, ""),
981 EventEnumVariation::Sync => write!(f, "Sync"),
982 EventEnumVariation::Stripped => write!(f, "Stripped"),
983 EventEnumVariation::Initial => write!(f, "Initial"),
984 }
985 }
986}