1
- use crate :: attributes:: { self , get_pyo3_options, CrateAttribute , FromPyWithAttribute } ;
1
+ use crate :: attributes:: {
2
+ self , get_pyo3_options, CrateAttribute , DefaultAttribute , FromPyWithAttribute ,
3
+ } ;
2
4
use crate :: utils:: Ctx ;
3
5
use proc_macro2:: TokenStream ;
4
- use quote:: { format_ident, quote} ;
6
+ use quote:: { format_ident, quote, ToTokens } ;
5
7
use syn:: {
6
8
ext:: IdentExt ,
7
9
parenthesized,
@@ -90,6 +92,7 @@ struct NamedStructField<'a> {
90
92
ident : & ' a syn:: Ident ,
91
93
getter : Option < FieldGetter > ,
92
94
from_py_with : Option < FromPyWithAttribute > ,
95
+ default : Option < DefaultAttribute > ,
93
96
}
94
97
95
98
struct TupleStructField {
@@ -193,6 +196,7 @@ impl<'a> Container<'a> {
193
196
ident,
194
197
getter : attrs. getter ,
195
198
from_py_with : attrs. from_py_with ,
199
+ default : attrs. default ,
196
200
} )
197
201
} )
198
202
. collect :: < Result < Vec < _ > > > ( ) ?;
@@ -346,18 +350,33 @@ impl<'a> Container<'a> {
346
350
quote ! ( #pyo3_path:: types:: PyAnyMethods :: get_item( obj, #pyo3_path:: intern!( obj. py( ) , #field_name) ) )
347
351
}
348
352
} ;
349
- let extractor = match & field. from_py_with {
350
- None => {
351
- quote ! ( #pyo3_path:: impl_:: frompyobject:: extract_struct_field( & #getter?, #struct_name, #field_name) ?)
352
- }
353
- Some ( FromPyWithAttribute {
354
- value : expr_path, ..
355
- } ) => {
356
- quote ! ( #pyo3_path:: impl_:: frompyobject:: extract_struct_field_with( #expr_path as fn ( _) -> _, & #getter?, #struct_name, #field_name) ?)
357
- }
353
+ let extractor = if let Some ( FromPyWithAttribute {
354
+ value : expr_path, ..
355
+ } ) = & field. from_py_with
356
+ {
357
+ quote ! ( #pyo3_path:: impl_:: frompyobject:: extract_struct_field_with( #expr_path as fn ( _) -> _, & value, #struct_name, #field_name) ?)
358
+ } else {
359
+ quote ! ( #pyo3_path:: impl_:: frompyobject:: extract_struct_field( & value, #struct_name, #field_name) ?)
360
+ } ;
361
+ let extracted = if let Some ( default) = & field. default {
362
+ let default_expr = if let Some ( default_expr) = & default. value {
363
+ default_expr. to_token_stream ( )
364
+ } else {
365
+ quote ! ( Default :: default ( ) )
366
+ } ;
367
+ quote ! ( if let Ok ( value) = #getter {
368
+ #extractor
369
+ } else {
370
+ #default_expr
371
+ } )
372
+ } else {
373
+ quote ! ( {
374
+ let value = #getter?;
375
+ #extractor
376
+ } )
358
377
} ;
359
378
360
- fields. push ( quote ! ( #ident: #extractor ) ) ;
379
+ fields. push ( quote ! ( #ident: #extracted ) ) ;
361
380
}
362
381
363
382
quote ! ( :: std:: result:: Result :: Ok ( #self_ty{ #fields} ) )
@@ -458,6 +477,7 @@ impl ContainerOptions {
458
477
struct FieldPyO3Attributes {
459
478
getter : Option < FieldGetter > ,
460
479
from_py_with : Option < FromPyWithAttribute > ,
480
+ default : Option < DefaultAttribute > ,
461
481
}
462
482
463
483
#[ derive( Clone , Debug ) ]
@@ -469,6 +489,7 @@ enum FieldGetter {
469
489
enum FieldPyO3Attribute {
470
490
Getter ( FieldGetter ) ,
471
491
FromPyWith ( FromPyWithAttribute ) ,
492
+ Default ( DefaultAttribute ) ,
472
493
}
473
494
474
495
impl Parse for FieldPyO3Attribute {
@@ -512,6 +533,8 @@ impl Parse for FieldPyO3Attribute {
512
533
}
513
534
} else if lookahead. peek ( attributes:: kw:: from_py_with) {
514
535
input. parse ( ) . map ( FieldPyO3Attribute :: FromPyWith )
536
+ } else if lookahead. peek ( attributes:: kw:: default) {
537
+ input. parse ( ) . map ( FieldPyO3Attribute :: Default )
515
538
} else {
516
539
Err ( lookahead. error ( ) )
517
540
}
@@ -523,6 +546,7 @@ impl FieldPyO3Attributes {
523
546
fn from_attrs ( attrs : & [ Attribute ] ) -> Result < Self > {
524
547
let mut getter = None ;
525
548
let mut from_py_with = None ;
549
+ let mut default = None ;
526
550
527
551
for attr in attrs {
528
552
if let Some ( pyo3_attrs) = get_pyo3_options ( attr) ? {
@@ -542,6 +566,13 @@ impl FieldPyO3Attributes {
542
566
) ;
543
567
from_py_with = Some ( from_py_with_attr) ;
544
568
}
569
+ FieldPyO3Attribute :: Default ( default_attr) => {
570
+ ensure_spanned ! (
571
+ default . is_none( ) ,
572
+ attr. span( ) => "`default` may only be provided once"
573
+ ) ;
574
+ default = Some ( default_attr) ;
575
+ }
545
576
}
546
577
}
547
578
}
@@ -550,6 +581,7 @@ impl FieldPyO3Attributes {
550
581
Ok ( FieldPyO3Attributes {
551
582
getter,
552
583
from_py_with,
584
+ default,
553
585
} )
554
586
}
555
587
}
0 commit comments