Skip to main content

near_lake_context_derive/
lib.rs

1#![doc = include_str!("../README.md")]
2use proc_macro::TokenStream;
3use quote::quote;
4
5#[proc_macro_derive(LakeContext)]
6pub fn lake_context_derive(input: TokenStream) -> TokenStream {
7    let input = syn::parse_macro_input!(input as syn::DeriveInput);
8
9    // Used in the quasi-quotation below as `#name`.
10    let name = input.ident;
11
12    // Build the trait impl.
13    // Iterate over all fields and for each field generate a call to `execute_before_run`.
14    // if the field is a an impl of LakeContext, then call `execute_before_run` on the struct.
15
16    let fields = if let syn::Data::Struct(syn::DataStruct {
17        fields: syn::Fields::Named(syn::FieldsNamed { named, .. }),
18        ..
19    }) = &input.data
20    {
21        named
22    } else {
23        unimplemented!();
24    };
25
26    let calls_before_run = fields
27        .iter()
28        .filter(|f| {
29            let ty = &f.ty;
30            if let syn::Type::Path(syn::TypePath { path, .. }) = ty {
31                if let Some(ident) = path.get_ident() {
32                    ident == "LakeContext"
33                } else {
34                    false
35                }
36            } else {
37                false
38            }
39        })
40        .map(|f| {
41            let name = &f.ident;
42            quote! { self.#name.execute_before_run(block); }
43        });
44
45    let calls_after_run = fields
46        .iter()
47        .rev()
48        .filter(|f| {
49            let ty = &f.ty;
50            if let syn::Type::Path(syn::TypePath { path, .. }) = ty {
51                if let Some(ident) = path.get_ident() {
52                    ident == "LakeContext"
53                } else {
54                    false
55                }
56            } else {
57                false
58            }
59        })
60        .map(|f| {
61            let name = &f.ident;
62            quote! { self.#name.execute_after_run(); }
63        });
64
65    let expanded = quote! {
66        // The generated impl.
67        impl near_lake_framework::LakeContextExt for #name {
68            fn execute_before_run(&self, block: &mut near_lake_primitives::block::Block) {
69                #( #calls_before_run )*
70            }
71
72            fn execute_after_run(&self) {
73                #( #calls_after_run )*
74            }
75        }
76    };
77
78    // Hand the output tokens back to the compiler.
79    proc_macro::TokenStream::from(expanded)
80}