@@ -3,8 +3,11 @@ use crate::{
33 AsObject , Context , Py , PyObject , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
44 builtins:: { PyTypeRef , builtin_func:: PyNativeMethod , type_} ,
55 class:: PyClassImpl ,
6+ common:: hash:: PyHash ,
67 function:: { FuncArgs , PyMethodDef , PyMethodFlags , PySetterValue } ,
7- types:: { Callable , GetDescriptor , Representable } ,
8+ types:: {
9+ Callable , Comparable , GetDescriptor , Hashable , InitFunc , PyComparisonOp , Representable ,
10+ } ,
811} ;
912use rustpython_common:: lock:: PyRwLock ;
1013
@@ -219,7 +222,7 @@ impl std::fmt::Debug for PyMemberDef {
219222 }
220223}
221224
222- // PyMemberDescrObject in CPython
225+ // = PyMemberDescrObject
223226#[ pyclass( name = "member_descriptor" , module = false ) ]
224227#[ derive( Debug ) ]
225228pub struct PyMemberDescriptor {
@@ -382,4 +385,201 @@ impl GetDescriptor for PyMemberDescriptor {
382385pub fn init ( ctx : & Context ) {
383386 PyMemberDescriptor :: extend_class ( ctx, ctx. types . member_descriptor_type ) ;
384387 PyMethodDescriptor :: extend_class ( ctx, ctx. types . method_descriptor_type ) ;
388+ PySlotWrapper :: extend_class ( ctx, ctx. types . wrapper_descriptor_type ) ;
389+ PyMethodWrapper :: extend_class ( ctx, ctx. types . method_wrapper_type ) ;
390+ }
391+
392+ // PySlotWrapper - wrapper_descriptor
393+
394+ /// wrapper_descriptor: wraps a slot function as a Python method
395+ // = PyWrapperDescrObject
396+ #[ pyclass( name = "wrapper_descriptor" , module = false ) ]
397+ #[ derive( Debug ) ]
398+ pub struct PySlotWrapper {
399+ pub typ : & ' static Py < PyType > ,
400+ pub name : & ' static PyStrInterned ,
401+ pub wrapped : InitFunc ,
402+ pub doc : Option < & ' static str > ,
403+ }
404+
405+ impl PyPayload for PySlotWrapper {
406+ fn class ( ctx : & Context ) -> & ' static Py < PyType > {
407+ ctx. types . wrapper_descriptor_type
408+ }
409+ }
410+
411+ impl GetDescriptor for PySlotWrapper {
412+ fn descr_get (
413+ zelf : PyObjectRef ,
414+ obj : Option < PyObjectRef > ,
415+ _cls : Option < PyObjectRef > ,
416+ vm : & VirtualMachine ,
417+ ) -> PyResult {
418+ match obj {
419+ None => Ok ( zelf) ,
420+ Some ( obj) if vm. is_none ( & obj) => Ok ( zelf) ,
421+ Some ( obj) => {
422+ let zelf = zelf. downcast :: < Self > ( ) . unwrap ( ) ;
423+ Ok ( PyMethodWrapper { wrapper : zelf, obj } . into_pyobject ( vm) )
424+ }
425+ }
426+ }
427+ }
428+
429+ impl Callable for PySlotWrapper {
430+ type Args = FuncArgs ;
431+
432+ fn call ( zelf : & Py < Self > , args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
433+ // list.__init__(l, [1,2,3]) form
434+ let ( obj, rest) : ( PyObjectRef , FuncArgs ) = args. bind ( vm) ?;
435+
436+ if !obj. fast_isinstance ( zelf. typ ) {
437+ return Err ( vm. new_type_error ( format ! (
438+ "descriptor '{}' requires a '{}' object but received a '{}'" ,
439+ zelf. name. as_str( ) ,
440+ zelf. typ. name( ) ,
441+ obj. class( ) . name( )
442+ ) ) ) ;
443+ }
444+
445+ ( zelf. wrapped ) ( obj, rest, vm) ?;
446+ Ok ( vm. ctx . none ( ) )
447+ }
448+ }
449+
450+ #[ pyclass(
451+ with( GetDescriptor , Callable , Representable ) ,
452+ flags( DISALLOW_INSTANTIATION )
453+ ) ]
454+ impl PySlotWrapper {
455+ #[ pygetset]
456+ fn __name__ ( & self ) -> & ' static PyStrInterned {
457+ self . name
458+ }
459+
460+ #[ pygetset]
461+ fn __qualname__ ( & self ) -> String {
462+ format ! ( "{}.{}" , self . typ. name( ) , self . name)
463+ }
464+
465+ #[ pygetset]
466+ fn __objclass__ ( & self ) -> PyTypeRef {
467+ self . typ . to_owned ( )
468+ }
469+
470+ #[ pygetset]
471+ fn __doc__ ( & self ) -> Option < & ' static str > {
472+ self . doc
473+ }
474+ }
475+
476+ impl Representable for PySlotWrapper {
477+ #[ inline]
478+ fn repr_str ( zelf : & Py < Self > , _vm : & VirtualMachine ) -> PyResult < String > {
479+ Ok ( format ! (
480+ "<slot wrapper '{}' of '{}' objects>" ,
481+ zelf. name. as_str( ) ,
482+ zelf. typ. name( )
483+ ) )
484+ }
485+ }
486+
487+ // PyMethodWrapper - method-wrapper
488+
489+ /// method-wrapper: a slot wrapper bound to an instance
490+ /// Returned when accessing l.__init__ on an instance
491+ #[ pyclass( name = "method-wrapper" , module = false , traverse) ]
492+ #[ derive( Debug ) ]
493+ pub struct PyMethodWrapper {
494+ pub wrapper : PyRef < PySlotWrapper > ,
495+ #[ pytraverse( skip) ]
496+ pub obj : PyObjectRef ,
497+ }
498+
499+ impl PyPayload for PyMethodWrapper {
500+ fn class ( ctx : & Context ) -> & ' static Py < PyType > {
501+ ctx. types . method_wrapper_type
502+ }
503+ }
504+
505+ impl Callable for PyMethodWrapper {
506+ type Args = FuncArgs ;
507+
508+ fn call ( zelf : & Py < Self > , args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
509+ ( zelf. wrapper . wrapped ) ( zelf. obj . clone ( ) , args, vm) ?;
510+ Ok ( vm. ctx . none ( ) )
511+ }
512+ }
513+
514+ #[ pyclass(
515+ with( Callable , Representable , Hashable , Comparable ) ,
516+ flags( DISALLOW_INSTANTIATION )
517+ ) ]
518+ impl PyMethodWrapper {
519+ #[ pygetset]
520+ fn __self__ ( & self ) -> PyObjectRef {
521+ self . obj . clone ( )
522+ }
523+
524+ #[ pygetset]
525+ fn __name__ ( & self ) -> & ' static PyStrInterned {
526+ self . wrapper . name
527+ }
528+
529+ #[ pygetset]
530+ fn __objclass__ ( & self ) -> PyTypeRef {
531+ self . wrapper . typ . to_owned ( )
532+ }
533+
534+ #[ pymethod]
535+ fn __reduce__ ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> PyResult {
536+ let builtins_getattr = vm. builtins . get_attr ( "getattr" , vm) ?;
537+ Ok ( vm
538+ . ctx
539+ . new_tuple ( vec ! [
540+ builtins_getattr,
541+ vm. ctx
542+ . new_tuple( vec![
543+ zelf. obj. clone( ) ,
544+ vm. ctx. new_str( zelf. wrapper. name. as_str( ) ) . into( ) ,
545+ ] )
546+ . into( ) ,
547+ ] )
548+ . into ( ) )
549+ }
550+ }
551+
552+ impl Representable for PyMethodWrapper {
553+ #[ inline]
554+ fn repr_str ( zelf : & Py < Self > , _vm : & VirtualMachine ) -> PyResult < String > {
555+ Ok ( format ! (
556+ "<method-wrapper '{}' of {} object at {:#x}>" ,
557+ zelf. wrapper. name. as_str( ) ,
558+ zelf. obj. class( ) . name( ) ,
559+ zelf. obj. get_id( )
560+ ) )
561+ }
562+ }
563+
564+ impl Hashable for PyMethodWrapper {
565+ fn hash ( zelf : & Py < Self > , vm : & VirtualMachine ) -> PyResult < PyHash > {
566+ let obj_hash = zelf. obj . hash ( vm) ?;
567+ let wrapper_hash = zelf. wrapper . as_object ( ) . get_id ( ) as PyHash ;
568+ Ok ( obj_hash ^ wrapper_hash)
569+ }
570+ }
571+
572+ impl Comparable for PyMethodWrapper {
573+ fn cmp (
574+ zelf : & Py < Self > ,
575+ other : & PyObject ,
576+ op : PyComparisonOp ,
577+ vm : & VirtualMachine ,
578+ ) -> PyResult < crate :: function:: PyComparisonValue > {
579+ op. eq_only ( || {
580+ let other = class_or_notimplemented ! ( Self , other) ;
581+ let eq = zelf. wrapper . is ( & other. wrapper ) && vm. bool_eq ( & zelf. obj , & other. obj ) ?;
582+ Ok ( eq. into ( ) )
583+ } )
584+ }
385585}
0 commit comments