hydro2_operator_derive/
lib.rs

1// ---------------- [ File: src/lib.rs ]
2#![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/// The main entry point for `[derive(Operator)]`.
28#[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    // Ensure struct (named, tuple, or unit)
36    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    // Parse operator(...) attributes => OperatorSpec
48    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    // Prepare generics
56    let mut generics = input_ast.generics.clone();
57
58    // Check if we need a lifetime `'a`
59    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        // Insert a `LifetimeParam` if it's not already present.
67        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    // Generate FooOpIO
79    let enum_def = generate_io_enum(
80        struct_ident,
81        &operator_spec,
82        uses_lifetime,
83        &quote! { #impl_generics },
84        &quote! { #type_generics },
85        &quote! { #where_clause },
86    );
87
88    // The enum ident is `FooOpIO`
89    let io_enum_ident = Ident::new(&format!("{}IO", struct_ident), struct_span);
90
91    // Generate `impl Operator<StructIO> for Struct`
92    let operator_impl = generate_operator_impl(
93        struct_ident,
94        &operator_spec,
95        &io_enum_ident,
96        &quote! { #impl_generics },
97        &quote! { #type_generics },
98        &quote! { #where_clause },
99    );
100
101    // Generate your new port-aware TryFrom/TryInto
102    let port_conversions = generate_port_aware_conversions(
103        &io_enum_ident,
104        &generics,
105        &operator_spec,
106    );
107
108    // **Now**: build the hidden signature type, e.g. `__FooOp__OperatorSignature`
109    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        &quote! { #impl_generics },
115        &quote! { #type_generics },
116        &quote! { #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}