agave_event_system_derive/
lib.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use {
4 proc_macro::TokenStream,
5 proc_macro_crate::{FoundCrate, crate_name},
6 proc_macro2::Span,
7 quote::{format_ident, quote},
8 syn::{DeriveInput, LitStr, parse::Parser, parse_macro_input},
9};
10
11#[proc_macro_attribute]
31pub fn event(args: TokenStream, item: TokenStream) -> TokenStream {
32 event_impl(args.into(), parse_macro_input!(item as DeriveInput))
33 .unwrap_or_else(syn::Error::into_compile_error)
34 .into()
35}
36
37fn event_impl(
38 args: proc_macro2::TokenStream,
39 input: DeriveInput,
40) -> syn::Result<proc_macro2::TokenStream> {
41 if !input.generics.params.is_empty() {
42 return Err(syn::Error::new_spanned(
43 &input.generics,
44 "Event cannot be derived for generic types on stable Rust; implement it by hand \
45 instead (see `agave_event_system::Event::QueueCell`)",
46 ));
47 }
48
49 let EventArgs {
50 max_serialized_size,
51 } = event_args(args)?;
52 let ident = &input.ident;
53 let event_system_crate = event_system_crate()?;
54 let event_macro_path = quote!(#event_system_crate::__private::event_macro);
55 let event_macro_path = LitStr::new(&event_macro_path.to_string(), Span::call_site());
56 let max_serialized_size = match max_serialized_size {
57 Some(max_serialized_size) => quote!(::core::option::Option::Some(#max_serialized_size)),
58 None => quote!(::core::option::Option::None),
59 };
60
61 Ok(quote! {
62 #[derive(
63 #event_system_crate::wincode::SchemaRead,
64 #event_system_crate::wincode::SchemaWrite,
65 #event_system_crate::wincode_dynamic::SchemaDynamic,
66 )]
67 #[wincode(crate = #event_macro_path)]
68 #input
69
70 impl #event_system_crate::Event for #ident {
71 type QueueCell = [u8; #event_system_crate::event_queue_cell_size(
72 <Self as #event_system_crate::wincode_dynamic::SchemaDynamic>::SERIALIZED_SIZE,
73 #max_serialized_size,
74 )];
75 }
76 })
77}
78
79fn event_system_crate() -> syn::Result<proc_macro2::TokenStream> {
80 match crate_name("agave-event-system") {
81 Ok(FoundCrate::Itself) => Ok(quote!(::agave_event_system)),
82 Ok(FoundCrate::Name(name)) => {
83 let ident = format_ident!("{}", name.replace('-', "_"));
84 Ok(quote!(::#ident))
85 }
86 Err(error) => Err(syn::Error::new(Span::call_site(), error)),
87 }
88}
89
90struct EventArgs {
91 max_serialized_size: Option<usize>,
92}
93
94fn event_args(args: proc_macro2::TokenStream) -> syn::Result<EventArgs> {
95 let mut max_serialized_size = None;
96 let parser = syn::meta::parser(|meta| {
97 if meta.path.is_ident("max_serialized_size") {
98 if max_serialized_size.is_some() {
99 return Err(meta.error("duplicate `max_serialized_size`"));
100 }
101 let value = meta.value()?.parse::<syn::LitInt>()?;
102 max_serialized_size = Some(value.base10_parse()?);
103 Ok(())
104 } else {
105 Err(meta.error("unsupported event attribute"))
106 }
107 });
108 parser.parse2(args)?;
109 Ok(EventArgs {
110 max_serialized_size,
111 })
112}