hydro2_operator_derive/
lib.rs1#![allow(unused_doc_comments)]
3#![allow(unused_imports)]
4#![allow(unused_variables)]
5#![feature(iter_intersperse)]
6#[macro_use] mod imports; use imports::*;
7
8xp!{build_execute_body}
9xp!{build_port_arms}
10xp!{errors}
11xp!{generate_io_enum}
12xp!{generate_operator_impl}
13xp!{generate_active_output_port_impl}
14xp!{operator_spec}
15xp!{operator_key_values}
16xp!{type_contains_lifetime_reference}
17xp!{generate_port_aware_conversions}
18xp!{generate_port_aware_try_into}
19xp!{generate_port_aware_try_from}
20xp!{generate_operator_signature_tokens}
21xp!{generate_port_try_into}
22xp!{generate_port_try_from}
23xp!{phantom_data_for_generics}
24
25type RawTokenStream = proc_macro::TokenStream;
26
27#[proc_macro_derive(Operator, attributes(operator))]
29pub fn derive_operator(input: RawTokenStream) -> RawTokenStream {
30
31 let input_ast = parse_macro_input!(input as DeriveInput);
32 let struct_ident = &input_ast.ident;
33 let struct_span = struct_ident.span();
34
35 match &input_ast.data {
37 Data::Struct(DataStruct { fields: Fields::Named(_), .. }) => {}
38 Data::Struct(DataStruct { fields: Fields::Unnamed(_), .. }) => {}
39 Data::Struct(DataStruct { fields: Fields::Unit, .. }) => {}
40 _ => {
41 return syn::Error::new(struct_span, "Operator derive can only be used on structs.")
42 .to_compile_error()
43 .into();
44 }
45 }
46
47 let operator_spec = match OperatorSpec::parse_operator_attrs(&input_ast.attrs, struct_span) {
49 Ok(spec) => spec,
50 Err(e) => {
51 return e.to_compile_error().into();
52 }
53 };
54
55 let mut generics = input_ast.generics.clone();
57
58 let uses_lifetime = operator_spec
60 .inputs()
61 .iter()
62 .any(|ty| contains_lifetime_reference(ty));
63
64 if uses_lifetime {
65 let lifetime_ident = Lifetime::new("'a", struct_span);
66 if !generics.params.iter().any(|param| match param {
68 GenericParam::Lifetime(lp) => lp.lifetime.ident == lifetime_ident.ident,
69 _ => false,
70 }) {
71 let lifetime_param = LifetimeParam::new(lifetime_ident);
72 generics.params.insert(0, GenericParam::Lifetime(lifetime_param));
73 }
74 }
75
76 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
77
78 let enum_def = generate_io_enum(
80 struct_ident,
81 &operator_spec,
82 uses_lifetime,
83 "e! { #impl_generics },
84 "e! { #type_generics },
85 "e! { #where_clause },
86 );
87
88 let io_enum_ident = Ident::new(&format!("{}IO", struct_ident), struct_span);
90
91 let operator_impl = generate_operator_impl(
93 struct_ident,
94 &operator_spec,
95 &io_enum_ident,
96 "e! { #impl_generics },
97 "e! { #type_generics },
98 "e! { #where_clause },
99 );
100
101 let port_conversions = generate_port_aware_conversions(
103 &io_enum_ident,
104 &generics,
105 &operator_spec,
106 );
107
108 let sig_ident = format_ident!("{}OperatorSignature", struct_ident);
110
111 let operator_sig_tokens = generate_operator_signature_tokens(
112 &sig_ident,
113 &operator_spec,
114 "e! { #impl_generics },
115 "e! { #type_generics },
116 "e! { #where_clause },
117 &generics,
118 );
119
120 let expanded = quote! {
121 #enum_def
122 #operator_impl
123 #port_conversions
124 #operator_sig_tokens
125 };
126
127 expanded.into()
128}