1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Ident, Variant};

#[proc_macro_attribute]
pub fn croncat_error(_attrs: TokenStream, input: TokenStream) -> TokenStream {
    let mut input = parse_macro_input!(input as DeriveInput);
    let enum_name = input.ident.clone();

    let mut is_croncat_error_present = false;
    if let Data::Enum(DataEnum {
        ref mut variants, ..
    }) = input.data
    {
        // See if they already have CronCatError variant
        for variant in variants.iter() {
            if variant.ident == Ident::new("CronCatError", variant.ident.span()) {
                is_croncat_error_present = true;
            }
        }

        if !is_croncat_error_present {
            // Add the CronCat variant, which looks like:
            // #[error("CronCat error: {err:?}")]
            // CronCatError {
            //   err: CronCatContractError
            // }
            let croncat_error_variant: Variant = syn::parse_quote! {
                #[error("CronCat error: {err:?}")]
                CronCatError {
                    err: croncat_integration_utils::error::CronCatContractError,
                }
            };
            variants.push(croncat_error_variant);
        }
    }

    // Add an impl for error propagation. Looks like:
    // impl From<CronCatContractError> for ContractError {
    //   fn from(error: CronCatContractError) -> Self {
    //     ContractError::CronCatError {
    //       err: error,
    //     }
    //   }
    // }
    let expanded = quote! {
        #input

        impl From<croncat_integration_utils::error::CronCatContractError> for #enum_name {
            fn from(error: croncat_integration_utils::error::CronCatContractError) -> Self {
                #enum_name::CronCatError {
                    err: error,
                }
            }
        }
    };

    TokenStream::from(expanded)
}