1+ use std:: ptr:: NonNull ;
2+
13use crossbeam_utils:: atomic:: AtomicCell ;
4+ use once_cell:: sync:: OnceCell ;
25
36use crate :: {
47 builtins:: { int, PyByteArray , PyBytes , PyComplex , PyFloat , PyInt , PyIntRef , PyStr } ,
@@ -12,6 +15,7 @@ type UnaryFunc<R = PyObjectRef> = AtomicCell<Option<fn(&PyNumber, &VirtualMachin
1215type BinaryFunc < R = PyObjectRef > =
1316 AtomicCell < Option < fn ( & PyNumber , & PyObject , & VirtualMachine ) -> PyResult < R > > > ;
1417
18+ #[ derive( Default ) ]
1519pub struct PyNumberMethods {
1620 /* Number implementations must check *both*
1721 arguments for proper type and implement the necessary conversions
@@ -124,36 +128,38 @@ impl PyNumberMethods {
124128pub struct PyNumber < ' a > {
125129 pub obj : & ' a PyObject ,
126130 // some fast path do not need methods, so we do lazy initialize
127- pub methods : Option < & ' static PyNumberMethods > ,
131+ methods : OnceCell < NonNull < PyNumberMethods > > ,
128132}
129133
130- impl < ' a > PyNumber < ' a > {
131- pub fn new ( obj : & ' a PyObject , vm : & VirtualMachine ) -> Self {
134+ impl < ' a > From < & ' a PyObject > for PyNumber < ' a > {
135+ fn from ( obj : & ' a PyObject ) -> Self {
132136 Self {
133137 obj,
134- methods : Self :: find_methods ( obj , vm ) ,
138+ methods : OnceCell :: new ( ) ,
135139 }
136140 }
137141}
138142
139143impl PyNumber < ' _ > {
140- pub fn find_methods ( obj : & PyObject , vm : & VirtualMachine ) -> Option < & ' static PyNumberMethods > {
141- let as_number = obj. class ( ) . mro_find_map ( |x| x. slots . as_number . load ( ) ) ;
142- as_number. map ( |f| f ( obj, vm) )
144+ pub fn methods ( & self ) -> & PyNumberMethods {
145+ let as_number = self . methods . get_or_init ( || {
146+ Self :: find_methods ( self . obj ) . unwrap_or ( NonNull :: from ( & PyNumberMethods :: NOT_IMPLEMENTED ) )
147+ } ) ;
148+ unsafe { as_number. as_ref ( ) }
143149 }
144150
145- pub fn methods ( & self ) -> & ' static PyNumberMethods {
146- self . methods . unwrap_or ( & PyNumberMethods :: NOT_IMPLEMENTED )
151+ fn find_methods < ' a > ( obj : & ' a PyObject ) -> Option < NonNull < PyNumberMethods > > {
152+ obj . class ( ) . mro_find_map ( |x| x . slots . as_number . load ( ) )
147153 }
148154
149155 // PyNumber_Check
150- pub fn check ( obj : & PyObject , vm : & VirtualMachine ) -> bool {
151- Self :: find_methods ( obj, vm ) . map_or ( false , |methods| {
152- methods . int . load ( ) . is_some ( )
153- || methods. index . load ( ) . is_some ( )
154- || methods. float . load ( ) . is_some ( )
155- || obj . payload_is :: < PyComplex > ( )
156- } )
156+ pub fn check < ' a > ( obj : & ' a PyObject , vm : & VirtualMachine ) -> bool {
157+ let num = PyNumber :: from ( obj) ;
158+ let methods = num . methods ( ) ;
159+ methods. int . load ( ) . is_some ( )
160+ || methods. index . load ( ) . is_some ( )
161+ || methods . float . load ( ) . is_some ( )
162+ || obj . payload_is :: < PyComplex > ( )
157163 }
158164
159165 // PyIndex_Check
@@ -207,7 +213,7 @@ impl PyNumber<'_> {
207213 // vm,
208214 // )?;
209215 let ret = f. invoke ( ( ) , vm) ?;
210- PyNumber :: new ( ret. as_ref ( ) , vm ) . index ( vm) . map_err ( |_| {
216+ PyNumber :: from ( ret. as_ref ( ) ) . index ( vm) . map_err ( |_| {
211217 vm. new_type_error ( format ! (
212218 "__trunc__ returned non-Integral (type {})" ,
213219 ret. class( )
0 commit comments