@@ -3,7 +3,18 @@ use quote::{format_ident, quote};
33use syn:: { DataEnum , Fields , Ident } ;
44
55/// Generate the zero-copy enum definition with type aliases for pattern matching
6- pub fn generate_z_enum ( z_enum_name : & Ident , enum_data : & DataEnum ) -> syn:: Result < TokenStream > {
6+ /// The `MUT` parameter controls whether to generate mutable or immutable variants
7+ pub fn generate_z_enum < const MUT : bool > (
8+ z_enum_name : & Ident ,
9+ enum_data : & DataEnum ,
10+ ) -> syn:: Result < TokenStream > {
11+ // Add Mut suffix when MUT is true
12+ let z_enum_name = if MUT {
13+ format_ident ! ( "{}Mut" , z_enum_name)
14+ } else {
15+ z_enum_name. clone ( )
16+ } ;
17+
718 // Collect type aliases for complex variants
819 let mut type_aliases = Vec :: new ( ) ;
920 let mut has_lifetime_dependent_variants = false ;
@@ -28,9 +39,21 @@ pub fn generate_z_enum(z_enum_name: &Ident, enum_data: &DataEnum) -> syn::Result
2839 has_lifetime_dependent_variants = true ;
2940
3041 // Create a type alias for this variant to enable pattern matching
31- let alias_name = format_ident ! ( "{}Type" , variant_name) ;
32- type_aliases. push ( quote ! {
33- pub type #alias_name<' a> = <#field_type as :: light_zero_copy:: traits:: ZeroCopyAt <' a>>:: ZeroCopyAt ;
42+ let alias_name = if MUT {
43+ format_ident ! ( "{}TypeMut" , variant_name)
44+ } else {
45+ format_ident ! ( "{}Type" , variant_name)
46+ } ;
47+
48+ // Generate appropriate type based on MUT
49+ type_aliases. push ( if MUT {
50+ quote ! {
51+ pub type #alias_name<' a> = <#field_type as :: light_zero_copy:: traits:: ZeroCopyAtMut <' a>>:: ZeroCopyAtMut ;
52+ }
53+ } else {
54+ quote ! {
55+ pub type #alias_name<' a> = <#field_type as :: light_zero_copy:: traits:: ZeroCopyAt <' a>>:: ZeroCopyAt ;
56+ }
3457 } ) ;
3558
3659 Ok ( quote ! { #variant_name( #alias_name<' a>) } )
@@ -58,17 +81,24 @@ pub fn generate_z_enum(z_enum_name: &Ident, enum_data: &DataEnum) -> syn::Result
5881 }
5982 } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
6083
84+ // For mutable enums, we don't derive Clone (can't clone mutable references)
85+ let derive_attrs = if MUT {
86+ quote ! { #[ derive( Debug , PartialEq ) ] }
87+ } else {
88+ quote ! { #[ derive( Debug , Clone , PartialEq ) ] }
89+ } ;
90+
6191 // Conditionally add lifetime parameter only if needed
6292 let enum_declaration = if has_lifetime_dependent_variants {
6393 quote ! {
64- #[ derive ( Debug , Clone , PartialEq ) ]
94+ #derive_attrs
6595 pub enum #z_enum_name<' a> {
6696 #( #variants, ) *
6797 }
6898 }
6999 } else {
70100 quote ! {
71- #[ derive ( Debug , Clone , PartialEq ) ]
101+ #derive_attrs
72102 pub enum #z_enum_name {
73103 #( #variants, ) *
74104 }
@@ -84,11 +114,36 @@ pub fn generate_z_enum(z_enum_name: &Ident, enum_data: &DataEnum) -> syn::Result
84114}
85115
86116/// Generate the deserialize implementation for the enum
87- pub fn generate_enum_deserialize_impl (
117+ /// The `MUT` parameter controls whether to generate mutable or immutable deserialization
118+ pub fn generate_enum_deserialize_impl < const MUT : bool > (
88119 original_name : & Ident ,
89120 z_enum_name : & Ident ,
90121 enum_data : & DataEnum ,
91122) -> syn:: Result < TokenStream > {
123+ // Add Mut suffix when MUT is true
124+ let z_enum_name = if MUT {
125+ format_ident ! ( "{}Mut" , z_enum_name)
126+ } else {
127+ z_enum_name. clone ( )
128+ } ;
129+
130+ // Choose trait and method based on MUT
131+ let ( trait_name, mutability, method_name, associated_type) = if MUT {
132+ (
133+ quote ! ( :: light_zero_copy:: traits:: ZeroCopyAtMut ) ,
134+ quote ! ( mut ) ,
135+ quote ! ( zero_copy_at_mut) ,
136+ quote ! ( ZeroCopyAtMut ) ,
137+ )
138+ } else {
139+ (
140+ quote ! ( :: light_zero_copy:: traits:: ZeroCopyAt ) ,
141+ quote ! ( ) ,
142+ quote ! ( zero_copy_at) ,
143+ quote ! ( ZeroCopyAt ) ,
144+ )
145+ } ;
146+
92147 // Check if any variants need lifetime parameters
93148 let mut has_lifetime_dependent_variants = false ;
94149
@@ -120,10 +175,21 @@ pub fn generate_enum_deserialize_impl(
120175 "Internal error: expected exactly one unnamed field but found none"
121176 ) ) ?
122177 . ty ;
178+
179+ // Use appropriate trait method based on MUT
180+ let deserialize_call = if MUT {
181+ quote ! {
182+ <#field_type as :: light_zero_copy:: traits:: ZeroCopyAtMut >:: zero_copy_at_mut( remaining_data) ?
183+ }
184+ } else {
185+ quote ! {
186+ <#field_type as :: light_zero_copy:: traits:: ZeroCopyAt >:: zero_copy_at( remaining_data) ?
187+ }
188+ } ;
189+
123190 Ok ( quote ! {
124191 #discriminant => {
125- let ( value, remaining_bytes) =
126- <#field_type as :: light_zero_copy:: traits:: ZeroCopyAt >:: zero_copy_at( remaining_data) ?;
192+ let ( value, remaining_bytes) = #deserialize_call;
127193 Ok ( ( #z_enum_name:: #variant_name( value) , remaining_bytes) )
128194 }
129195 } )
@@ -148,13 +214,14 @@ pub fn generate_enum_deserialize_impl(
148214 } ;
149215
150216 Ok ( quote ! {
151- impl <' a> :: light_zero_copy :: traits :: ZeroCopyAt <' a> for #original_name {
152- type ZeroCopyAt = #type_annotation;
217+ impl <' a> #trait_name <' a> for #original_name {
218+ type #associated_type = #type_annotation;
153219
154- fn zero_copy_at (
155- data: & ' a [ u8 ] ,
156- ) -> Result <( Self :: ZeroCopyAt , & ' a [ u8 ] ) , :: light_zero_copy:: errors:: ZeroCopyError > {
220+ fn #method_name (
221+ data: & ' a #mutability [ u8 ] ,
222+ ) -> Result <( Self :: #associated_type , & ' a #mutability [ u8 ] ) , :: light_zero_copy:: errors:: ZeroCopyError > {
157223 // Read discriminant (first 1 byte for borsh enum)
224+ // Note: Discriminant is ALWAYS immutable for safety, even in mutable deserialization
158225 if data. is_empty( ) {
159226 return Err ( :: light_zero_copy:: errors:: ZeroCopyError :: ArraySize (
160227 1 ,
@@ -163,7 +230,7 @@ pub fn generate_enum_deserialize_impl(
163230 }
164231
165232 let discriminant = data[ 0 ] ;
166- let remaining_data = & data[ 1 ..] ;
233+ let remaining_data = & #mutability data[ 1 ..] ;
167234
168235 match discriminant {
169236 #( #match_arms) *
@@ -175,11 +242,19 @@ pub fn generate_enum_deserialize_impl(
175242}
176243
177244/// Generate the ZeroCopyStructInner implementation for the enum
178- pub fn generate_enum_zero_copy_struct_inner (
245+ /// The `MUT` parameter controls whether to generate mutable or immutable struct inner trait
246+ pub fn generate_enum_zero_copy_struct_inner < const MUT : bool > (
179247 original_name : & Ident ,
180248 z_enum_name : & Ident ,
181249 enum_data : & DataEnum ,
182250) -> syn:: Result < TokenStream > {
251+ // Add Mut suffix when MUT is true
252+ let z_enum_name = if MUT {
253+ format_ident ! ( "{}Mut" , z_enum_name)
254+ } else {
255+ z_enum_name. clone ( )
256+ } ;
257+
183258 // Check if any variants need lifetime parameters
184259 let has_lifetime_dependent_variants = enum_data. variants . iter ( ) . any (
185260 |variant| matches ! ( & variant. fields, Fields :: Unnamed ( fields) if fields. unnamed. len( ) == 1 ) ,
@@ -192,9 +267,18 @@ pub fn generate_enum_zero_copy_struct_inner(
192267 quote ! { #z_enum_name }
193268 } ;
194269
195- Ok ( quote ! {
196- impl :: light_zero_copy:: traits:: ZeroCopyStructInner for #original_name {
197- type ZeroCopyInner = #type_annotation;
270+ // Generate appropriate trait impl based on MUT
271+ Ok ( if MUT {
272+ quote ! {
273+ impl :: light_zero_copy:: traits:: ZeroCopyStructInnerMut for #original_name {
274+ type ZeroCopyInnerMut = #type_annotation;
275+ }
276+ }
277+ } else {
278+ quote ! {
279+ impl :: light_zero_copy:: traits:: ZeroCopyStructInner for #original_name {
280+ type ZeroCopyInner = #type_annotation;
281+ }
198282 }
199283 } )
200284}
0 commit comments