@@ -21,6 +21,9 @@ struct StructOpts {
21
21
/// List of attributes to apply to the generated Ref type.
22
22
#[ darling( default ) ]
23
23
ref_attributes : Option < NestedMetaList > ,
24
+ /// List of attributes to apply to the generated MutRef type.
25
+ #[ darling( default ) ]
26
+ ref_mut_attributes : Option < NestedMetaList > ,
24
27
/// Error type and expression to use for casting methods.
25
28
#[ darling( default ) ]
26
29
cast_error : CastErrOpts ,
@@ -197,6 +200,37 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
197
200
} ;
198
201
output_items. push ( ref_ty. into ( ) ) ;
199
202
203
+ // Construct a top-level mutable reference type.
204
+ // TODO: check that variants aren't called `RefMut`
205
+ let ref_mut_ty_name = format_ident ! ( "{}RefMut" , type_name) ;
206
+ let ref_mut_ty_lifetime = Lifetime :: new ( "'__superstruct" , Span :: call_site ( ) ) ;
207
+ // Muahaha, this is dank.
208
+ // Inject the generated lifetime into the top-level type's generics.
209
+ let mut ref_mut_ty_decl_generics = decl_generics. clone ( ) ;
210
+ ref_mut_ty_decl_generics. params . insert (
211
+ 0 ,
212
+ GenericParam :: Lifetime ( LifetimeDef :: new ( ref_mut_ty_lifetime. clone ( ) ) ) ,
213
+ ) ;
214
+ let ( ref_mut_impl_generics, ref_mut_ty_generics, _) = & ref_mut_ty_decl_generics. split_for_impl ( ) ;
215
+
216
+ // Prepare the attributes for the ref type.
217
+ let ref_mut_attributes = opts
218
+ . ref_mut_attributes
219
+ . as_ref ( )
220
+ . map_or ( & [ ] [ ..] , |attrs| & attrs. metas ) ;
221
+
222
+ let ref_mut_ty = quote ! {
223
+ #(
224
+ #[ #ref_mut_attributes]
225
+ ) *
226
+ #visibility enum #ref_mut_ty_name #ref_mut_ty_decl_generics #where_clause {
227
+ #(
228
+ #variant_names( & #ref_mut_ty_lifetime mut #struct_names #ty_generics) ,
229
+ ) *
230
+ }
231
+ } ;
232
+ output_items. push ( ref_mut_ty. into ( ) ) ;
233
+
200
234
// Construct the main impl block.
201
235
let getters = common_fields. iter ( ) . map ( |( field, getter_opts) | {
202
236
let field_name = field. ident . as_ref ( ) . expect ( "named fields only" ) ;
@@ -220,6 +254,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
220
254
& variant_names,
221
255
field_name,
222
256
& field. ty ,
257
+ None ,
223
258
getter_opts,
224
259
)
225
260
} ) ;
@@ -255,6 +290,14 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
255
290
) *
256
291
}
257
292
}
293
+ pub fn to_mut<#ref_mut_ty_lifetime>( & #ref_mut_ty_lifetime mut self ) -> #ref_mut_ty_name #ref_mut_ty_generics {
294
+ match self {
295
+ #(
296
+ #type_name:: #variant_names( ref mut inner)
297
+ => #ref_mut_ty_name:: #variant_names( inner) ,
298
+ ) *
299
+ }
300
+ }
258
301
#(
259
302
#cast_methods
260
303
) *
@@ -296,6 +339,30 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
296
339
} ;
297
340
output_items. push ( ref_impl_block. into ( ) ) ;
298
341
342
+ // Construct the impl block for the *MutRef type.
343
+ let ref_mut_getters = common_fields. iter ( )
344
+ . filter ( |( _, getter_opts) | !getter_opts. no_mut )
345
+ . map ( |( field, getter_opts) | {
346
+ let field_name = field. ident . as_ref ( ) . expect ( "named fields only" ) ;
347
+ make_mut_field_getter (
348
+ & ref_mut_ty_name,
349
+ & variant_names,
350
+ field_name,
351
+ & field. ty ,
352
+ Some ( & ref_mut_ty_lifetime) ,
353
+ getter_opts,
354
+ )
355
+ } ) ;
356
+
357
+ let ref_mut_impl_block = quote ! {
358
+ impl #ref_mut_impl_generics #ref_mut_ty_name #ref_mut_ty_generics #where_clause {
359
+ #(
360
+ #ref_mut_getters
361
+ ) *
362
+ }
363
+ } ;
364
+ output_items. push ( ref_mut_impl_block. into ( ) ) ;
365
+
299
366
TokenStream :: from_iter ( output_items)
300
367
}
301
368
@@ -342,12 +409,23 @@ fn make_mut_field_getter(
342
409
variant_names : & [ Ident ] ,
343
410
field_name : & Ident ,
344
411
field_type : & Type ,
412
+ lifetime : Option < & Lifetime > ,
345
413
getter_opts : & GetterOpts ,
346
414
) -> proc_macro2:: TokenStream {
347
415
let fn_name = format_ident ! ( "{}_mut" , getter_opts. rename. as_ref( ) . unwrap_or( field_name) ) ;
416
+ let return_type= if let Some ( lifetime) = lifetime {
417
+ quote ! { & #lifetime mut #field_type}
418
+ } else {
419
+ quote ! { & mut #field_type}
420
+ } ;
421
+ let param= if let Some ( lifetime) = lifetime {
422
+ quote ! { & #lifetime mut self }
423
+ } else {
424
+ quote ! { & mut self }
425
+ } ;
348
426
let return_expr = quote ! { & mut inner. #field_name } ;
349
427
quote ! {
350
- pub fn #fn_name( & mut self ) -> & mut #field_type {
428
+ pub fn #fn_name( #param ) -> #return_type {
351
429
match self {
352
430
#(
353
431
#type_name:: #variant_names( ref mut inner) => {
0 commit comments