11use super :: { type_, PyClassMethod , PyStaticMethod , PyStr , PyStrInterned , PyStrRef , PyType } ;
22use crate :: {
3- builtins:: PyBoundMethod ,
43 class:: PyClassImpl ,
54 function:: { FuncArgs , IntoPyNativeFunc , PyNativeFunc } ,
65 types:: { Callable , Constructor , GetDescriptor , Representable , Unconstructible } ,
76 AsObject , Context , Py , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
87} ;
98use std:: fmt;
109
10+ #[ derive( Clone ) ]
1111pub struct PyNativeFuncDef {
12- pub func : PyNativeFunc ,
12+ pub func : & ' static PyNativeFunc ,
1313 pub name : & ' static PyStrInterned ,
1414 pub doc : Option < PyStrRef > ,
1515}
1616
1717impl PyNativeFuncDef {
18- pub fn new ( func : PyNativeFunc , name : & ' static PyStrInterned ) -> Self {
18+ pub fn new ( func : & ' static PyNativeFunc , name : & ' static PyStrInterned ) -> Self {
1919 Self {
2020 func,
2121 name,
@@ -29,14 +29,36 @@ impl PyNativeFuncDef {
2929 }
3030
3131 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+ }
3346 }
3447 pub fn build_function ( self , ctx : & Context ) -> PyRef < PyBuiltinFunction > {
3548 self . into_function ( ) . into_ref ( ctx)
3649 }
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 > {
3856 PyRef :: new_ref (
39- PyBuiltinMethod { value : self , class } ,
57+ PyBuiltinMethod {
58+ value : self ,
59+ class,
60+ is_classmethod,
61+ } ,
4062 ctx. types . method_descriptor_type . to_owned ( ) ,
4163 None ,
4264 )
@@ -47,23 +69,26 @@ impl PyNativeFuncDef {
4769 class : & ' static Py < PyType > ,
4870 ) -> PyRef < PyClassMethod > {
4971 // TODO: classmethod_descriptor
50- let callable = self . build_method ( ctx, class) . into ( ) ;
72+ let callable = self . build_method ( ctx, class, true ) . into ( ) ;
5173 PyClassMethod :: new_ref ( callable, ctx)
5274 }
5375 pub fn build_staticmethod (
5476 self ,
5577 ctx : & Context ,
5678 class : & ' static Py < PyType > ,
5779 ) -> PyRef < PyStaticMethod > {
58- let callable = self . build_method ( ctx, class) . into ( ) ;
80+ // TODO
81+ let callable = self . build_method ( ctx, class, true ) . into ( ) ;
5982 PyStaticMethod :: new_ref ( callable, ctx)
6083 }
6184}
6285
6386#[ pyclass( name = "builtin_function_or_method" , module = false ) ]
6487pub struct PyBuiltinFunction {
88+ zelf : Option < PyObjectRef > ,
6589 value : PyNativeFuncDef ,
6690 module : Option < PyObjectRef > ,
91+ is_classmethod : bool ,
6792}
6893
6994impl PyPayload for PyBuiltinFunction {
@@ -78,15 +103,6 @@ impl fmt::Debug for PyBuiltinFunction {
78103 }
79104}
80105
81- impl From < PyNativeFuncDef > for PyBuiltinFunction {
82- fn from ( value : PyNativeFuncDef ) -> Self {
83- Self {
84- value,
85- module : None ,
86- }
87- }
88- }
89-
90106impl PyBuiltinFunction {
91107 pub fn with_module ( mut self , module : PyObjectRef ) -> Self {
92108 self . module = Some ( module) ;
@@ -101,15 +117,18 @@ impl PyBuiltinFunction {
101117 )
102118 }
103119
104- pub fn as_func ( & self ) -> & PyNativeFunc {
105- & self . value . func
120+ pub fn as_func ( & self ) -> & ' static PyNativeFunc {
121+ self . value . func
106122 }
107123}
108124
109125impl Callable for PyBuiltinFunction {
110126 type Args = FuncArgs ;
111127 #[ 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+ }
113132 ( zelf. value . func ) ( vm, args)
114133 }
115134}
@@ -125,8 +144,22 @@ impl PyBuiltinFunction {
125144 self . value . name . to_owned ( )
126145 }
127146 #[ 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+ }
130163 }
131164 #[ pygetset( magic) ]
132165 fn doc ( & self ) -> Option < PyStrRef > {
@@ -173,6 +206,7 @@ impl Unconstructible for PyBuiltinFunction {}
173206pub struct PyBuiltinMethod {
174207 value : PyNativeFuncDef ,
175208 class : & ' static Py < PyType > ,
209+ is_classmethod : bool ,
176210}
177211
178212impl PyPayload for PyBuiltinMethod {
@@ -200,8 +234,20 @@ impl GetDescriptor for PyBuiltinMethod {
200234 } ;
201235 let r = if vm. is_none ( & obj) && !Self :: _cls_is ( & cls, obj. class ( ) ) {
202236 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 ( )
203244 } 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 ( )
205251 } ;
206252 Ok ( r)
207253 }
@@ -225,7 +271,7 @@ impl PyBuiltinMethod {
225271 where
226272 F : IntoPyNativeFunc < FKind > ,
227273 {
228- ctx. make_func_def ( name, f) . build_method ( ctx, class)
274+ ctx. make_func_def ( name, f) . build_method ( ctx, class, false )
229275 }
230276}
231277
0 commit comments