whisky_macros/data/
enum_constr.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput, Fields};
4
5pub fn derive_plutus_data_to_json(input: TokenStream) -> TokenStream {
6    let input = parse_macro_input!(input as DeriveInput);
7    let name = &input.ident;
8    
9    let implementation = match &input.data {
10        Data::Enum(data_enum) => {
11            let match_arms = data_enum.variants.iter().enumerate().map(|(index, variant)| {
12                let variant_name = &variant.ident;
13                let full_variant_path = quote! { #name::#variant_name };
14                
15                match &variant.fields {
16                    Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
17                        // Single field tuple variant like UserSpotAccount(Account)
18                        quote! {
19                            #full_variant_path(field) => ::whisky::data::Constr::new(#index as u64, field.clone()).to_json()
20                        }
21                    }
22                    Fields::Unnamed(fields) => {
23                        // Multiple fields tuple variant like MintCancelOrderIntent(UserAccount, ByteString)
24                        let field_count = fields.unnamed.len();
25                        let field_names: Vec<_> = (0..field_count).map(|i| syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site())).collect();
26                        
27                        let pattern = quote! { #(#field_names),* };
28                        let tuple = quote! { (#(#field_names.clone()),*) };
29                        
30                        quote! {
31                            #full_variant_path(#pattern) => ::whisky::data::Constr::new(#index as u64, Box::new(#tuple)).to_json()
32                        }
33                    }
34                    Fields::Named(_) => {
35                        // Named fields - you can extend this if needed
36                        panic!("Named fields not supported yet");
37                    }
38                    Fields::Unit => {
39                        // Unit variant like SomeVariant
40                        quote! {
41                            #full_variant_path => ::whisky::data::Constr::new(#index as u64, ()).to_json()
42                        }
43                    }
44                }
45            });
46
47            quote! {
48                impl ::whisky::data::PlutusDataJson for #name {
49                    fn to_json(&self) -> ::serde_json::Value {
50                        match self {
51                            #(#match_arms,)*
52                        }
53                    }
54                    
55                    fn to_json_string(&self) -> String {
56                        self.to_json().to_string()
57                    }
58
59                    fn to_constr_field(&self) -> Vec<::serde_json::Value> {
60                        vec![self.to_json()]
61                    }
62                }
63            }
64        }
65        _ => {
66            panic!("PlutusDataToJson can only be derived for enums");
67        }
68    };
69
70    implementation.into()
71}