@@ -6,7 +6,7 @@ use syn::{ext::IdentExt, spanned::Spanned, Ident, Result};
6
6
7
7
use crate :: utils:: Ctx ;
8
8
use crate :: {
9
- attributes:: { TextSignatureAttribute , TextSignatureAttributeValue } ,
9
+ attributes:: { FromPyWithAttribute , TextSignatureAttribute , TextSignatureAttributeValue } ,
10
10
deprecations:: { Deprecation , Deprecations } ,
11
11
params:: { impl_arg_params, Holders } ,
12
12
pyfunction:: {
@@ -17,19 +17,109 @@ use crate::{
17
17
} ;
18
18
19
19
#[ derive( Clone , Debug ) ]
20
- pub struct FnArg < ' a > {
20
+ pub struct RegularArg < ' a > {
21
21
pub name : & ' a syn:: Ident ,
22
22
pub ty : & ' a syn:: Type ,
23
- pub optional : Option < & ' a syn:: Type > ,
24
- pub default : Option < syn:: Expr > ,
25
- pub py : bool ,
26
- pub attrs : PyFunctionArgPyO3Attributes ,
27
- pub is_varargs : bool ,
28
- pub is_kwargs : bool ,
29
- pub is_cancel_handle : bool ,
23
+ pub from_py_with : Option < FromPyWithAttribute > ,
24
+ pub default_value : Option < syn:: Expr > ,
25
+ pub option_wrapped_type : Option < & ' a syn:: Type > ,
26
+ }
27
+
28
+ /// Pythons *args argument
29
+ #[ derive( Clone , Debug ) ]
30
+ pub struct VarargsArg < ' a > {
31
+ pub name : & ' a syn:: Ident ,
32
+ pub ty : & ' a syn:: Type ,
33
+ }
34
+
35
+ /// Pythons **kwarg argument
36
+ #[ derive( Clone , Debug ) ]
37
+ pub struct KwargsArg < ' a > {
38
+ pub name : & ' a syn:: Ident ,
39
+ pub ty : & ' a syn:: Type ,
40
+ }
41
+
42
+ #[ derive( Clone , Debug ) ]
43
+ pub struct CancelHandleArg < ' a > {
44
+ pub name : & ' a syn:: Ident ,
45
+ pub ty : & ' a syn:: Type ,
46
+ }
47
+
48
+ #[ derive( Clone , Debug ) ]
49
+ pub struct PyArg < ' a > {
50
+ pub name : & ' a syn:: Ident ,
51
+ pub ty : & ' a syn:: Type ,
52
+ }
53
+
54
+ #[ derive( Clone , Debug ) ]
55
+ pub enum FnArg < ' a > {
56
+ Regular ( RegularArg < ' a > ) ,
57
+ VarArgs ( VarargsArg < ' a > ) ,
58
+ KwArgs ( KwargsArg < ' a > ) ,
59
+ Py ( PyArg < ' a > ) ,
60
+ CancelHandle ( CancelHandleArg < ' a > ) ,
30
61
}
31
62
32
63
impl < ' a > FnArg < ' a > {
64
+ pub fn name ( & self ) -> & ' a syn:: Ident {
65
+ match self {
66
+ FnArg :: Regular ( RegularArg { name, .. } ) => name,
67
+ FnArg :: VarArgs ( VarargsArg { name, .. } ) => name,
68
+ FnArg :: KwArgs ( KwargsArg { name, .. } ) => name,
69
+ FnArg :: Py ( PyArg { name, .. } ) => name,
70
+ FnArg :: CancelHandle ( CancelHandleArg { name, .. } ) => name,
71
+ }
72
+ }
73
+
74
+ pub fn ty ( & self ) -> & ' a syn:: Type {
75
+ match self {
76
+ FnArg :: Regular ( RegularArg { ty, .. } ) => ty,
77
+ FnArg :: VarArgs ( VarargsArg { ty, .. } ) => ty,
78
+ FnArg :: KwArgs ( KwargsArg { ty, .. } ) => ty,
79
+ FnArg :: Py ( PyArg { ty, .. } ) => ty,
80
+ FnArg :: CancelHandle ( CancelHandleArg { ty, .. } ) => ty,
81
+ }
82
+ }
83
+
84
+ #[ allow( clippy:: wrong_self_convention) ]
85
+ pub fn from_py_with ( & self ) -> Option < & FromPyWithAttribute > {
86
+ if let FnArg :: Regular ( RegularArg { from_py_with, .. } ) = self {
87
+ from_py_with. as_ref ( )
88
+ } else {
89
+ None
90
+ }
91
+ }
92
+
93
+ pub fn to_varargs_mut ( & mut self ) -> Result < & mut Self > {
94
+ if let Self :: Regular ( RegularArg {
95
+ name,
96
+ ty,
97
+ option_wrapped_type : None ,
98
+ ..
99
+ } ) = self
100
+ {
101
+ * self = Self :: VarArgs ( VarargsArg { name, ty } ) ;
102
+ Ok ( self )
103
+ } else {
104
+ bail_spanned ! ( self . name( ) . span( ) => "args cannot be optional" )
105
+ }
106
+ }
107
+
108
+ pub fn to_kwargs_mut ( & mut self ) -> Result < & mut Self > {
109
+ if let Self :: Regular ( RegularArg {
110
+ name,
111
+ ty,
112
+ option_wrapped_type : Some ( ..) ,
113
+ ..
114
+ } ) = self
115
+ {
116
+ * self = Self :: KwArgs ( KwargsArg { name, ty } ) ;
117
+ Ok ( self )
118
+ } else {
119
+ bail_spanned ! ( self . name( ) . span( ) => "kwargs must be Option<_>" )
120
+ }
121
+ }
122
+
33
123
/// Transforms a rust fn arg parsed with syn into a method::FnArg
34
124
pub fn parse ( arg : & ' a mut syn:: FnArg ) -> Result < Self > {
35
125
match arg {
@@ -41,32 +131,43 @@ impl<'a> FnArg<'a> {
41
131
bail_spanned ! ( cap. ty. span( ) => IMPL_TRAIT_ERR ) ;
42
132
}
43
133
44
- let arg_attrs = PyFunctionArgPyO3Attributes :: from_attrs ( & mut cap. attrs ) ?;
134
+ let PyFunctionArgPyO3Attributes {
135
+ from_py_with,
136
+ cancel_handle,
137
+ } = PyFunctionArgPyO3Attributes :: from_attrs ( & mut cap. attrs ) ?;
45
138
let ident = match & * cap. pat {
46
139
syn:: Pat :: Ident ( syn:: PatIdent { ident, .. } ) => ident,
47
140
other => return Err ( handle_argument_error ( other) ) ,
48
141
} ;
49
142
50
- let is_cancel_handle = arg_attrs. cancel_handle . is_some ( ) ;
143
+ if utils:: is_python ( & cap. ty ) {
144
+ return Ok ( Self :: Py ( PyArg {
145
+ name : ident,
146
+ ty : & cap. ty ,
147
+ } ) ) ;
148
+ }
51
149
52
- Ok ( FnArg {
150
+ if cancel_handle. is_some ( ) {
151
+ // `PyFunctionArgPyO3Attributes::from_attrs` validates that
152
+ // only compatible attributes are specified, either
153
+ // `cancel_handle` or `from_py_with`, dublicates and any
154
+ // combination of the two are already rejected.
155
+ return Ok ( Self :: CancelHandle ( CancelHandleArg {
156
+ name : ident,
157
+ ty : & cap. ty ,
158
+ } ) ) ;
159
+ }
160
+
161
+ Ok ( Self :: Regular ( RegularArg {
53
162
name : ident,
54
163
ty : & cap. ty ,
55
- optional : utils:: option_type_argument ( & cap. ty ) ,
56
- default : None ,
57
- py : utils:: is_python ( & cap. ty ) ,
58
- attrs : arg_attrs,
59
- is_varargs : false ,
60
- is_kwargs : false ,
61
- is_cancel_handle,
62
- } )
164
+ from_py_with,
165
+ default_value : None ,
166
+ option_wrapped_type : utils:: option_type_argument ( & cap. ty ) ,
167
+ } ) )
63
168
}
64
169
}
65
170
}
66
-
67
- pub fn is_regular ( & self ) -> bool {
68
- !self . py && !self . is_cancel_handle && !self . is_kwargs && !self . is_varargs
69
- }
70
171
}
71
172
72
173
fn handle_argument_error ( pat : & syn:: Pat ) -> syn:: Error {
@@ -492,12 +593,14 @@ impl<'a> FnSpec<'a> {
492
593
. signature
493
594
. arguments
494
595
. iter ( )
495
- . filter ( |arg| arg. is_cancel_handle ) ;
596
+ . filter ( |arg| matches ! ( arg, FnArg :: CancelHandle ( .. ) ) ) ;
496
597
let cancel_handle = cancel_handle_iter. next ( ) ;
497
- if let Some ( arg) = cancel_handle {
498
- ensure_spanned ! ( self . asyncness. is_some( ) , arg. name. span( ) => "`cancel_handle` attribute can only be used with `async fn`" ) ;
499
- if let Some ( arg2) = cancel_handle_iter. next ( ) {
500
- bail_spanned ! ( arg2. name. span( ) => "`cancel_handle` may only be specified once" ) ;
598
+ if let Some ( FnArg :: CancelHandle ( CancelHandleArg { name, .. } ) ) = cancel_handle {
599
+ ensure_spanned ! ( self . asyncness. is_some( ) , name. span( ) => "`cancel_handle` attribute can only be used with `async fn`" ) ;
600
+ if let Some ( FnArg :: CancelHandle ( CancelHandleArg { name, .. } ) ) =
601
+ cancel_handle_iter. next ( )
602
+ {
603
+ bail_spanned ! ( name. span( ) => "`cancel_handle` may only be specified once" ) ;
501
604
}
502
605
}
503
606
@@ -605,14 +708,10 @@ impl<'a> FnSpec<'a> {
605
708
. signature
606
709
. arguments
607
710
. iter ( )
608
- . map ( |arg| {
609
- if arg. py {
610
- quote ! ( py)
611
- } else if arg. is_cancel_handle {
612
- quote ! ( __cancel_handle)
613
- } else {
614
- unreachable ! ( )
615
- }
711
+ . map ( |arg| match arg {
712
+ FnArg :: Py ( ..) => quote ! ( py) ,
713
+ FnArg :: CancelHandle ( ..) => quote ! ( __cancel_handle) ,
714
+ _ => unreachable ! ( "`CallingConvention::Noargs` should not contain any arguments (reaching Python) except for `self`, which is handled below." ) ,
616
715
} )
617
716
. collect ( ) ;
618
717
let call = rust_call ( args, & mut holders) ;
@@ -635,7 +734,7 @@ impl<'a> FnSpec<'a> {
635
734
}
636
735
CallingConvention :: Fastcall => {
637
736
let mut holders = Holders :: new ( ) ;
638
- let ( arg_convert, args) = impl_arg_params ( self , cls, true , & mut holders, ctx) ? ;
737
+ let ( arg_convert, args) = impl_arg_params ( self , cls, true , & mut holders, ctx) ;
639
738
let call = rust_call ( args, & mut holders) ;
640
739
let init_holders = holders. init_holders ( ctx) ;
641
740
let check_gil_refs = holders. check_gil_refs ( ) ;
@@ -660,7 +759,7 @@ impl<'a> FnSpec<'a> {
660
759
}
661
760
CallingConvention :: Varargs => {
662
761
let mut holders = Holders :: new ( ) ;
663
- let ( arg_convert, args) = impl_arg_params ( self , cls, false , & mut holders, ctx) ? ;
762
+ let ( arg_convert, args) = impl_arg_params ( self , cls, false , & mut holders, ctx) ;
664
763
let call = rust_call ( args, & mut holders) ;
665
764
let init_holders = holders. init_holders ( ctx) ;
666
765
let check_gil_refs = holders. check_gil_refs ( ) ;
@@ -684,7 +783,7 @@ impl<'a> FnSpec<'a> {
684
783
}
685
784
CallingConvention :: TpNew => {
686
785
let mut holders = Holders :: new ( ) ;
687
- let ( arg_convert, args) = impl_arg_params ( self , cls, false , & mut holders, ctx) ? ;
786
+ let ( arg_convert, args) = impl_arg_params ( self , cls, false , & mut holders, ctx) ;
688
787
let self_arg = self
689
788
. tp
690
789
. self_arg ( cls, ExtractErrorMode :: Raise , & mut holders, ctx) ;
0 commit comments