@@ -3,36 +3,30 @@ use crate::{
33 dict:: { PyDictItems , PyDictKeys , PyDictValues } ,
44 PyDict , PyStrInterned ,
55 } ,
6- common:: lock:: OnceCell ,
76 convert:: ToPyResult ,
87 AsObject , PyObject , PyObjectRef , PyResult , VirtualMachine ,
98} ;
109
1110// Mapping protocol
1211// https://docs.python.org/3/c-api/mapping.html
1312#[ allow( clippy:: type_complexity) ]
14- #[ derive( Default , Copy , Clone ) ]
1513pub struct PyMappingMethods {
1614 pub length : Option < fn ( & PyMapping , & VirtualMachine ) -> PyResult < usize > > ,
1715 pub subscript : Option < fn ( & PyMapping , & PyObject , & VirtualMachine ) -> PyResult > ,
1816 pub ass_subscript :
1917 Option < fn ( & PyMapping , & PyObject , Option < PyObjectRef > , & VirtualMachine ) -> PyResult < ( ) > > ,
2018}
2119
20+ impl PyMappingMethods {
21+ fn check ( & self ) -> bool {
22+ self . subscript . is_some ( )
23+ }
24+ }
25+
2226#[ derive( Clone ) ]
2327pub struct PyMapping < ' a > {
2428 pub obj : & ' a PyObject ,
25- methods : OnceCell < PyMappingMethods > ,
26- }
27-
28- impl < ' a > From < & ' a PyObject > for PyMapping < ' a > {
29- #[ inline( always) ]
30- fn from ( obj : & ' a PyObject ) -> Self {
31- Self {
32- obj,
33- methods : OnceCell :: new ( ) ,
34- }
35- }
29+ pub methods : & ' static PyMappingMethods ,
3630}
3731
3832impl AsRef < PyObject > for PyMapping < ' _ > {
@@ -43,47 +37,47 @@ impl AsRef<PyObject> for PyMapping<'_> {
4337}
4438
4539impl < ' a > PyMapping < ' a > {
40+ #[ inline]
41+ pub fn new ( obj : & ' a PyObject , vm : & VirtualMachine ) -> Option < Self > {
42+ let methods = Self :: find_methods ( obj, vm) ?;
43+ Some ( Self { obj, methods } )
44+ }
45+
4646 #[ inline( always) ]
47- pub fn with_methods ( obj : & ' a PyObject , methods : PyMappingMethods ) -> Self {
48- Self {
49- obj,
50- methods : OnceCell :: from ( methods) ,
51- }
47+ pub fn with_methods ( obj : & ' a PyObject , methods : & ' static PyMappingMethods ) -> Self {
48+ Self { obj, methods }
5249 }
5350
5451 pub fn try_protocol ( obj : & ' a PyObject , vm : & VirtualMachine ) -> PyResult < Self > {
55- let zelf = Self :: from ( obj) ;
56- if zelf. check ( vm) {
57- Ok ( zelf)
58- } else {
59- Err ( vm. new_type_error ( format ! ( "{} is not a mapping object" , zelf. obj. class( ) ) ) )
52+ if let Some ( methods) = Self :: find_methods ( obj, vm) {
53+ if methods. check ( ) {
54+ return Ok ( Self :: with_methods ( obj, methods) ) ;
55+ }
6056 }
57+
58+ Err ( vm. new_type_error ( format ! ( "{} is not a mapping object" , obj. class( ) ) ) )
6159 }
6260}
6361
6462impl PyMapping < ' _ > {
6563 // PyMapping::Check
6664 #[ inline]
67- pub fn check ( & self , vm : & VirtualMachine ) -> bool {
68- self . methods ( vm) . subscript . is_some ( )
69- }
70-
71- pub fn methods ( & self , vm : & VirtualMachine ) -> & PyMappingMethods {
72- self . methods . get_or_init ( || {
73- if let Some ( f) = self
74- . obj
75- . class ( )
76- . mro_find_map ( |cls| cls. slots . as_mapping . load ( ) )
77- {
78- f ( self . obj , vm)
79- } else {
80- PyMappingMethods :: default ( )
81- }
82- } )
65+ pub fn check ( obj : & PyObject , vm : & VirtualMachine ) -> bool {
66+ Self :: find_methods ( obj, vm)
67+ . and_then ( |m| m. subscript )
68+ . is_some ( )
69+ }
70+
71+ pub fn find_methods ( obj : & PyObject , vm : & VirtualMachine ) -> Option < & ' static PyMappingMethods > {
72+ if let Some ( f) = obj. class ( ) . mro_find_map ( |cls| cls. slots . as_mapping . load ( ) ) {
73+ Some ( f ( obj, vm) )
74+ } else {
75+ None
76+ }
8377 }
8478
8579 pub fn length_opt ( & self , vm : & VirtualMachine ) -> Option < PyResult < usize > > {
86- self . methods ( vm ) . length . map ( |f| f ( self , vm) )
80+ self . methods . length . map ( |f| f ( self , vm) )
8781 }
8882
8983 pub fn length ( & self , vm : & VirtualMachine ) -> PyResult < usize > {
@@ -110,7 +104,7 @@ impl PyMapping<'_> {
110104
111105 fn _subscript ( & self , needle : & PyObject , vm : & VirtualMachine ) -> PyResult {
112106 let f = self
113- . methods ( vm )
107+ . methods
114108 . subscript
115109 . ok_or_else ( || vm. new_type_error ( format ! ( "{} is not a mapping" , self . obj. class( ) ) ) ) ?;
116110 f ( self , needle, vm)
@@ -122,7 +116,7 @@ impl PyMapping<'_> {
122116 value : Option < PyObjectRef > ,
123117 vm : & VirtualMachine ,
124118 ) -> PyResult < ( ) > {
125- let f = self . methods ( vm ) . ass_subscript . ok_or_else ( || {
119+ let f = self . methods . ass_subscript . ok_or_else ( || {
126120 vm. new_type_error ( format ! (
127121 "'{}' object does not support item assignment" ,
128122 self . obj. class( )
0 commit comments