@@ -3,7 +3,18 @@ use quote::{format_ident, quote};
3
3
use syn:: { DataEnum , Fields , Ident } ;
4
4
5
5
/// 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
+
7
18
// Collect type aliases for complex variants
8
19
let mut type_aliases = Vec :: new ( ) ;
9
20
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
28
39
has_lifetime_dependent_variants = true ;
29
40
30
41
// 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
+ }
34
57
} ) ;
35
58
36
59
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
58
81
}
59
82
} ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
60
83
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
+
61
91
// Conditionally add lifetime parameter only if needed
62
92
let enum_declaration = if has_lifetime_dependent_variants {
63
93
quote ! {
64
- #[ derive ( Debug , Clone , PartialEq ) ]
94
+ #derive_attrs
65
95
pub enum #z_enum_name<' a> {
66
96
#( #variants, ) *
67
97
}
68
98
}
69
99
} else {
70
100
quote ! {
71
- #[ derive ( Debug , Clone , PartialEq ) ]
101
+ #derive_attrs
72
102
pub enum #z_enum_name {
73
103
#( #variants, ) *
74
104
}
@@ -84,11 +114,36 @@ pub fn generate_z_enum(z_enum_name: &Ident, enum_data: &DataEnum) -> syn::Result
84
114
}
85
115
86
116
/// 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 > (
88
119
original_name : & Ident ,
89
120
z_enum_name : & Ident ,
90
121
enum_data : & DataEnum ,
91
122
) -> 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
+
92
147
// Check if any variants need lifetime parameters
93
148
let mut has_lifetime_dependent_variants = false ;
94
149
@@ -120,10 +175,21 @@ pub fn generate_enum_deserialize_impl(
120
175
"Internal error: expected exactly one unnamed field but found none"
121
176
) ) ?
122
177
. 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
+
123
190
Ok ( quote ! {
124
191
#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;
127
193
Ok ( ( #z_enum_name:: #variant_name( value) , remaining_bytes) )
128
194
}
129
195
} )
@@ -148,13 +214,14 @@ pub fn generate_enum_deserialize_impl(
148
214
} ;
149
215
150
216
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;
153
219
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 > {
157
223
// Read discriminant (first 1 byte for borsh enum)
224
+ // Note: Discriminant is ALWAYS immutable for safety, even in mutable deserialization
158
225
if data. is_empty( ) {
159
226
return Err ( :: light_zero_copy:: errors:: ZeroCopyError :: ArraySize (
160
227
1 ,
@@ -163,7 +230,7 @@ pub fn generate_enum_deserialize_impl(
163
230
}
164
231
165
232
let discriminant = data[ 0 ] ;
166
- let remaining_data = & data[ 1 ..] ;
233
+ let remaining_data = & #mutability data[ 1 ..] ;
167
234
168
235
match discriminant {
169
236
#( #match_arms) *
@@ -175,11 +242,19 @@ pub fn generate_enum_deserialize_impl(
175
242
}
176
243
177
244
/// 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 > (
179
247
original_name : & Ident ,
180
248
z_enum_name : & Ident ,
181
249
enum_data : & DataEnum ,
182
250
) -> 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
+
183
258
// Check if any variants need lifetime parameters
184
259
let has_lifetime_dependent_variants = enum_data. variants . iter ( ) . any (
185
260
|variant| matches ! ( & variant. fields, Fields :: Unnamed ( fields) if fields. unnamed. len( ) == 1 ) ,
@@ -192,9 +267,18 @@ pub fn generate_enum_zero_copy_struct_inner(
192
267
quote ! { #z_enum_name }
193
268
} ;
194
269
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
+ }
198
282
}
199
283
} )
200
284
}
0 commit comments