|
1 | 1 | //! Defines conversions between Rust and Python types.
|
2 | 2 | use crate::err::PyResult;
|
| 3 | +use crate::ffi_ptr_ext::FfiPtrExt; |
3 | 4 | #[cfg(feature = "experimental-inspect")]
|
4 | 5 | use crate::inspect::types::TypeInfo;
|
5 | 6 | use crate::pyclass::boolean_struct::False;
|
6 | 7 | use crate::types::any::PyAnyMethods;
|
7 |
| -use crate::types::PyTuple; |
| 8 | +use crate::types::{PyDict, PyString, PyTuple}; |
8 | 9 | use crate::{
|
9 | 10 | ffi, Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyErr, PyObject, PyRef, PyRefMut, Python,
|
10 | 11 | };
|
@@ -172,6 +173,93 @@ pub trait IntoPy<T>: Sized {
|
172 | 173 | fn type_output() -> TypeInfo {
|
173 | 174 | TypeInfo::Any
|
174 | 175 | }
|
| 176 | + |
| 177 | + // The following methods are helpers to use the vectorcall API where possible. |
| 178 | + // They are overridden on tuples to perform a vectorcall. |
| 179 | + // Be careful when you're implementing these: they can never refer to `Bound` call methods, |
| 180 | + // as those refer to these methods, so this will create an infinite recursion. |
| 181 | + #[doc(hidden)] |
| 182 | + #[inline] |
| 183 | + fn __py_call_vectorcall1<'py>( |
| 184 | + self, |
| 185 | + py: Python<'py>, |
| 186 | + function: Borrowed<'_, 'py, PyAny>, |
| 187 | + _: private::Token, |
| 188 | + ) -> PyResult<Bound<'py, PyAny>> |
| 189 | + where |
| 190 | + Self: IntoPy<Py<PyTuple>>, |
| 191 | + { |
| 192 | + #[inline] |
| 193 | + fn inner<'py>( |
| 194 | + py: Python<'py>, |
| 195 | + function: Borrowed<'_, 'py, PyAny>, |
| 196 | + args: Bound<'py, PyTuple>, |
| 197 | + ) -> PyResult<Bound<'py, PyAny>> { |
| 198 | + unsafe { |
| 199 | + ffi::PyObject_Call(function.as_ptr(), args.as_ptr(), std::ptr::null_mut()) |
| 200 | + .assume_owned_or_err(py) |
| 201 | + } |
| 202 | + } |
| 203 | + inner( |
| 204 | + py, |
| 205 | + function, |
| 206 | + <Self as IntoPy<Py<PyTuple>>>::into_py(self, py).into_bound(py), |
| 207 | + ) |
| 208 | + } |
| 209 | + |
| 210 | + #[doc(hidden)] |
| 211 | + #[inline] |
| 212 | + fn __py_call_vectorcall<'py>( |
| 213 | + self, |
| 214 | + py: Python<'py>, |
| 215 | + function: Borrowed<'_, 'py, PyAny>, |
| 216 | + kwargs: Option<Borrowed<'_, '_, PyDict>>, |
| 217 | + _: private::Token, |
| 218 | + ) -> PyResult<Bound<'py, PyAny>> |
| 219 | + where |
| 220 | + Self: IntoPy<Py<PyTuple>>, |
| 221 | + { |
| 222 | + #[inline] |
| 223 | + fn inner<'py>( |
| 224 | + py: Python<'py>, |
| 225 | + function: Borrowed<'_, 'py, PyAny>, |
| 226 | + args: Bound<'py, PyTuple>, |
| 227 | + kwargs: Option<Borrowed<'_, '_, PyDict>>, |
| 228 | + ) -> PyResult<Bound<'py, PyAny>> { |
| 229 | + unsafe { |
| 230 | + ffi::PyObject_Call( |
| 231 | + function.as_ptr(), |
| 232 | + args.as_ptr(), |
| 233 | + kwargs.map_or_else(std::ptr::null_mut, |kwargs| kwargs.as_ptr()), |
| 234 | + ) |
| 235 | + .assume_owned_or_err(py) |
| 236 | + } |
| 237 | + } |
| 238 | + inner( |
| 239 | + py, |
| 240 | + function, |
| 241 | + <Self as IntoPy<Py<PyTuple>>>::into_py(self, py).into_bound(py), |
| 242 | + kwargs, |
| 243 | + ) |
| 244 | + } |
| 245 | + |
| 246 | + #[doc(hidden)] |
| 247 | + #[inline] |
| 248 | + fn __py_call_method_vectorcall1<'py>( |
| 249 | + self, |
| 250 | + _py: Python<'py>, |
| 251 | + object: Borrowed<'_, 'py, PyAny>, |
| 252 | + method_name: Bound<'py, PyString>, |
| 253 | + _: private::Token, |
| 254 | + ) -> PyResult<Bound<'py, PyAny>> |
| 255 | + where |
| 256 | + Self: IntoPy<Py<PyTuple>>, |
| 257 | + { |
| 258 | + // Don't `self.into_py()`! This will lose the optimization of vectorcall. |
| 259 | + object |
| 260 | + .getattr(method_name) |
| 261 | + .and_then(|method| method.call1(self)) |
| 262 | + } |
175 | 263 | }
|
176 | 264 |
|
177 | 265 | /// Defines a conversion from a Rust type to a Python object, which may fail.
|
@@ -502,6 +590,52 @@ impl IntoPy<Py<PyTuple>> for () {
|
502 | 590 | fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
|
503 | 591 | PyTuple::empty(py).unbind()
|
504 | 592 | }
|
| 593 | + |
| 594 | + #[inline] |
| 595 | + fn __py_call_vectorcall1<'py>( |
| 596 | + self, |
| 597 | + py: Python<'py>, |
| 598 | + function: Borrowed<'_, 'py, PyAny>, |
| 599 | + _: private::Token, |
| 600 | + ) -> PyResult<Bound<'py, PyAny>> { |
| 601 | + unsafe { ffi::compat::PyObject_CallNoArgs(function.as_ptr()).assume_owned_or_err(py) } |
| 602 | + } |
| 603 | + |
| 604 | + #[inline] |
| 605 | + fn __py_call_vectorcall<'py>( |
| 606 | + self, |
| 607 | + py: Python<'py>, |
| 608 | + function: Borrowed<'_, 'py, PyAny>, |
| 609 | + kwargs: Option<Borrowed<'_, '_, PyDict>>, |
| 610 | + _: private::Token, |
| 611 | + ) -> PyResult<Bound<'py, PyAny>> { |
| 612 | + unsafe { |
| 613 | + match kwargs { |
| 614 | + Some(kwargs) => ffi::PyObject_Call( |
| 615 | + function.as_ptr(), |
| 616 | + PyTuple::empty(py).as_ptr(), |
| 617 | + kwargs.as_ptr(), |
| 618 | + ) |
| 619 | + .assume_owned_or_err(py), |
| 620 | + None => ffi::compat::PyObject_CallNoArgs(function.as_ptr()).assume_owned_or_err(py), |
| 621 | + } |
| 622 | + } |
| 623 | + } |
| 624 | + |
| 625 | + #[inline] |
| 626 | + #[allow(clippy::used_underscore_binding)] |
| 627 | + fn __py_call_method_vectorcall1<'py>( |
| 628 | + self, |
| 629 | + py: Python<'py>, |
| 630 | + object: Borrowed<'_, 'py, PyAny>, |
| 631 | + method_name: Bound<'py, PyString>, |
| 632 | + _: private::Token, |
| 633 | + ) -> PyResult<Bound<'py, PyAny>> { |
| 634 | + unsafe { |
| 635 | + ffi::compat::PyObject_CallMethodNoArgs(object.as_ptr(), method_name.as_ptr()) |
| 636 | + .assume_owned_or_err(py) |
| 637 | + } |
| 638 | + } |
505 | 639 | }
|
506 | 640 |
|
507 | 641 | impl<'py> IntoPyObject<'py> for () {
|
|
0 commit comments