Avoid attribute lookup overhead for __bool__ if the unlimited API is available.
This commit is contained in:
parent
8133aaa5d8
commit
3e10d64fa2
|
@ -146,6 +146,7 @@ impl PyAny {
|
||||||
///
|
///
|
||||||
/// To avoid repeated temporary allocations of Python strings, the [`intern!`] macro can be used
|
/// To avoid repeated temporary allocations of Python strings, the [`intern!`] macro can be used
|
||||||
/// to intern `attr_name`.
|
/// to intern `attr_name`.
|
||||||
|
#[allow(dead_code)] // Currently only used with num-complex+abi3, so dead without that.
|
||||||
pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<&PyAny>>
|
pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<&PyAny>>
|
||||||
where
|
where
|
||||||
N: IntoPy<Py<PyString>>,
|
N: IntoPy<Py<PyString>>,
|
||||||
|
|
|
@ -81,12 +81,32 @@ impl<'source> FromPyObject<'source> for bool {
|
||||||
return Ok(obj.is_true());
|
return Ok(obj.is_true());
|
||||||
}
|
}
|
||||||
|
|
||||||
let meth = obj
|
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||||
.lookup_special(intern!(obj.py(), "__bool__"))?
|
unsafe {
|
||||||
.ok_or_else(|| PyTypeError::new_err("object has no __bool__ magic method"))?;
|
let ptr = obj.as_ptr();
|
||||||
|
|
||||||
let obj = meth.call0()?.downcast::<PyBool>()?;
|
if let Some(tp_as_number) = (*(*ptr).ob_type).tp_as_number.as_ref() {
|
||||||
Ok(obj.is_true())
|
if let Some(nb_bool) = tp_as_number.nb_bool {
|
||||||
|
match (nb_bool)(ptr) {
|
||||||
|
0 => return Ok(false),
|
||||||
|
1 => return Ok(true),
|
||||||
|
_ => return Err(crate::PyErr::fetch(obj.py())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(PyTypeError::new_err("object has no __bool__ magic method"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||||
|
{
|
||||||
|
let meth = obj
|
||||||
|
.lookup_special(crate::intern!(obj.py(), "__bool__"))?
|
||||||
|
.ok_or_else(|| PyTypeError::new_err("object has no __bool__ magic method"))?;
|
||||||
|
|
||||||
|
let obj = meth.call0()?.downcast::<PyBool>()?;
|
||||||
|
Ok(obj.is_true())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "experimental-inspect")]
|
#[cfg(feature = "experimental-inspect")]
|
||||||
|
@ -145,10 +165,11 @@ class D:
|
||||||
assert!(a.extract::<bool>().unwrap());
|
assert!(a.extract::<bool>().unwrap());
|
||||||
|
|
||||||
let b = module.getattr("B").unwrap().call0().unwrap();
|
let b = module.getattr("B").unwrap().call0().unwrap();
|
||||||
assert_eq!(
|
assert!(matches!(
|
||||||
b.extract::<bool>().unwrap_err().to_string(),
|
&*b.extract::<bool>().unwrap_err().to_string(),
|
||||||
"TypeError: 'str' object cannot be converted to 'PyBool'",
|
"TypeError: 'str' object cannot be converted to 'PyBool'"
|
||||||
);
|
| "TypeError: __bool__ should return bool, returned str"
|
||||||
|
));
|
||||||
|
|
||||||
let c = module.getattr("C").unwrap().call0().unwrap();
|
let c = module.getattr("C").unwrap().call0().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in New Issue