1
1
use super :: { type_, PyClassMethod , PyStaticMethod , PyStr , PyStrInterned , PyStrRef , PyType } ;
2
2
use crate :: {
3
- builtins:: PyBoundMethod ,
4
3
class:: PyClassImpl ,
5
4
function:: { FuncArgs , IntoPyNativeFunc , PyNativeFunc } ,
6
5
types:: { Callable , Constructor , GetDescriptor , Representable , Unconstructible } ,
7
6
AsObject , Context , Py , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
8
7
} ;
9
8
use std:: fmt;
10
9
10
+ #[ derive( Clone ) ]
11
11
pub struct PyNativeFuncDef {
12
- pub func : PyNativeFunc ,
12
+ pub func : & ' static PyNativeFunc ,
13
13
pub name : & ' static PyStrInterned ,
14
14
pub doc : Option < PyStrRef > ,
15
15
}
16
16
17
17
impl PyNativeFuncDef {
18
- pub fn new ( func : PyNativeFunc , name : & ' static PyStrInterned ) -> Self {
18
+ pub fn new ( func : & ' static PyNativeFunc , name : & ' static PyStrInterned ) -> Self {
19
19
Self {
20
20
func,
21
21
name,
@@ -29,14 +29,36 @@ impl PyNativeFuncDef {
29
29
}
30
30
31
31
pub fn into_function ( self ) -> PyBuiltinFunction {
32
- self . into ( )
32
+ PyBuiltinFunction {
33
+ zelf : None ,
34
+ value : self ,
35
+ module : None ,
36
+ is_classmethod : false ,
37
+ }
38
+ }
39
+ pub fn into_method ( self , obj : PyObjectRef , is_classmethod : bool ) -> PyBuiltinFunction {
40
+ PyBuiltinFunction {
41
+ zelf : Some ( obj) ,
42
+ value : self ,
43
+ module : None ,
44
+ is_classmethod,
45
+ }
33
46
}
34
47
pub fn build_function ( self , ctx : & Context ) -> PyRef < PyBuiltinFunction > {
35
48
self . into_function ( ) . into_ref ( ctx)
36
49
}
37
- pub fn build_method ( self , ctx : & Context , class : & ' static Py < PyType > ) -> PyRef < PyBuiltinMethod > {
50
+ pub fn build_method (
51
+ self ,
52
+ ctx : & Context ,
53
+ class : & ' static Py < PyType > ,
54
+ is_classmethod : bool ,
55
+ ) -> PyRef < PyBuiltinMethod > {
38
56
PyRef :: new_ref (
39
- PyBuiltinMethod { value : self , class } ,
57
+ PyBuiltinMethod {
58
+ value : self ,
59
+ class,
60
+ is_classmethod,
61
+ } ,
40
62
ctx. types . method_descriptor_type . to_owned ( ) ,
41
63
None ,
42
64
)
@@ -47,23 +69,26 @@ impl PyNativeFuncDef {
47
69
class : & ' static Py < PyType > ,
48
70
) -> PyRef < PyClassMethod > {
49
71
// TODO: classmethod_descriptor
50
- let callable = self . build_method ( ctx, class) . into ( ) ;
72
+ let callable = self . build_method ( ctx, class, true ) . into ( ) ;
51
73
PyClassMethod :: new_ref ( callable, ctx)
52
74
}
53
75
pub fn build_staticmethod (
54
76
self ,
55
77
ctx : & Context ,
56
78
class : & ' static Py < PyType > ,
57
79
) -> PyRef < PyStaticMethod > {
58
- let callable = self . build_method ( ctx, class) . into ( ) ;
80
+ // TODO
81
+ let callable = self . build_method ( ctx, class, true ) . into ( ) ;
59
82
PyStaticMethod :: new_ref ( callable, ctx)
60
83
}
61
84
}
62
85
63
86
#[ pyclass( name = "builtin_function_or_method" , module = false ) ]
64
87
pub struct PyBuiltinFunction {
88
+ zelf : Option < PyObjectRef > ,
65
89
value : PyNativeFuncDef ,
66
90
module : Option < PyObjectRef > ,
91
+ is_classmethod : bool ,
67
92
}
68
93
69
94
impl PyPayload for PyBuiltinFunction {
@@ -78,15 +103,6 @@ impl fmt::Debug for PyBuiltinFunction {
78
103
}
79
104
}
80
105
81
- impl From < PyNativeFuncDef > for PyBuiltinFunction {
82
- fn from ( value : PyNativeFuncDef ) -> Self {
83
- Self {
84
- value,
85
- module : None ,
86
- }
87
- }
88
- }
89
-
90
106
impl PyBuiltinFunction {
91
107
pub fn with_module ( mut self , module : PyObjectRef ) -> Self {
92
108
self . module = Some ( module) ;
@@ -101,15 +117,18 @@ impl PyBuiltinFunction {
101
117
)
102
118
}
103
119
104
- pub fn as_func ( & self ) -> & PyNativeFunc {
105
- & self . value . func
120
+ pub fn as_func ( & self ) -> & ' static PyNativeFunc {
121
+ self . value . func
106
122
}
107
123
}
108
124
109
125
impl Callable for PyBuiltinFunction {
110
126
type Args = FuncArgs ;
111
127
#[ inline]
112
- fn call ( zelf : & Py < Self > , args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
128
+ fn call ( zelf : & Py < Self > , mut args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
129
+ if let Some ( z) = & zelf. zelf {
130
+ args. prepend_arg ( z. clone ( ) ) ;
131
+ }
113
132
( zelf. value . func ) ( vm, args)
114
133
}
115
134
}
@@ -125,8 +144,22 @@ impl PyBuiltinFunction {
125
144
self . value . name . to_owned ( )
126
145
}
127
146
#[ pygetset( magic) ]
128
- fn qualname ( & self ) -> PyStrRef {
129
- self . name ( )
147
+ fn qualname ( & self , vm : & VirtualMachine ) -> PyStrRef {
148
+ if let Some ( zelf) = & self . zelf {
149
+ // TODO: is_classmethod 이면 zelf 의 이름을 알 방법이 없나?
150
+ let prefix = if self . is_classmethod {
151
+ zelf. get_attr ( "__qualname__" , vm)
152
+ . unwrap ( )
153
+ . str ( vm)
154
+ . unwrap ( )
155
+ . to_string ( )
156
+ } else {
157
+ zelf. class ( ) . name ( ) . to_string ( )
158
+ } ;
159
+ PyStr :: from ( format ! ( "{}.{}" , prefix, & self . value. name) ) . into_ref ( & vm. ctx )
160
+ } else {
161
+ self . name ( )
162
+ }
130
163
}
131
164
#[ pygetset( magic) ]
132
165
fn doc ( & self ) -> Option < PyStrRef > {
@@ -173,6 +206,7 @@ impl Unconstructible for PyBuiltinFunction {}
173
206
pub struct PyBuiltinMethod {
174
207
value : PyNativeFuncDef ,
175
208
class : & ' static Py < PyType > ,
209
+ is_classmethod : bool ,
176
210
}
177
211
178
212
impl PyPayload for PyBuiltinMethod {
@@ -200,8 +234,20 @@ impl GetDescriptor for PyBuiltinMethod {
200
234
} ;
201
235
let r = if vm. is_none ( & obj) && !Self :: _cls_is ( & cls, obj. class ( ) ) {
202
236
zelf
237
+ } else if _zelf. is_classmethod {
238
+ _zelf
239
+ . value
240
+ . clone ( )
241
+ . into_method ( cls. unwrap ( ) , _zelf. is_classmethod )
242
+ . into_ref ( & vm. ctx )
243
+ . into ( )
203
244
} else {
204
- PyBoundMethod :: new_ref ( obj, zelf, & vm. ctx ) . into ( )
245
+ _zelf
246
+ . value
247
+ . clone ( )
248
+ . into_method ( obj, _zelf. is_classmethod )
249
+ . into_ref ( & vm. ctx )
250
+ . into ( )
205
251
} ;
206
252
Ok ( r)
207
253
}
@@ -225,7 +271,7 @@ impl PyBuiltinMethod {
225
271
where
226
272
F : IntoPyNativeFunc < FKind > ,
227
273
{
228
- ctx. make_func_def ( name, f) . build_method ( ctx, class)
274
+ ctx. make_func_def ( name, f) . build_method ( ctx, class, false )
229
275
}
230
276
}
231
277
0 commit comments