pyo3/impl_/
pymethods.rs

1use crate::exceptions::PyStopAsyncIteration;
2use crate::gil::LockGIL;
3use crate::impl_::callback::IntoPyCallbackOutput;
4use crate::impl_::panic::PanicTrap;
5use crate::impl_::pycell::{PyClassObject, PyClassObjectLayout};
6use crate::internal::get_slot::{get_slot, TP_BASE, TP_CLEAR, TP_TRAVERSE};
7use crate::pycell::impl_::PyClassBorrowChecker as _;
8use crate::pycell::{PyBorrowError, PyBorrowMutError};
9use crate::pyclass::boolean_struct::False;
10use crate::types::any::PyAnyMethods;
11use crate::types::PyType;
12use crate::{
13    ffi, Bound, DowncastError, Py, PyAny, PyClass, PyClassInitializer, PyErr, PyObject, PyRef,
14    PyRefMut, PyResult, PyTraverseError, PyTypeCheck, PyVisit, Python,
15};
16use std::ffi::CStr;
17use std::fmt;
18use std::marker::PhantomData;
19use std::os::raw::{c_int, c_void};
20use std::panic::{catch_unwind, AssertUnwindSafe};
21use std::ptr::null_mut;
22
23use super::trampoline;
24use crate::internal_tricks::{clear_eq, traverse_eq};
25
26/// Python 3.8 and up - __ipow__ has modulo argument correctly populated.
27#[cfg(Py_3_8)]
28#[repr(transparent)]
29pub struct IPowModulo(*mut ffi::PyObject);
30
31/// Python 3.7 and older - __ipow__ does not have modulo argument correctly populated.
32#[cfg(not(Py_3_8))]
33#[repr(transparent)]
34pub struct IPowModulo(#[allow(dead_code)] std::mem::MaybeUninit<*mut ffi::PyObject>);
35
36/// Helper to use as pymethod ffi definition
37#[allow(non_camel_case_types)]
38pub type ipowfunc = unsafe extern "C" fn(
39    arg1: *mut ffi::PyObject,
40    arg2: *mut ffi::PyObject,
41    arg3: IPowModulo,
42) -> *mut ffi::PyObject;
43
44impl IPowModulo {
45    #[cfg(Py_3_8)]
46    #[inline]
47    pub fn as_ptr(self) -> *mut ffi::PyObject {
48        self.0
49    }
50
51    #[cfg(not(Py_3_8))]
52    #[inline]
53    pub fn as_ptr(self) -> *mut ffi::PyObject {
54        // Safety: returning a borrowed pointer to Python `None` singleton
55        unsafe { ffi::Py_None() }
56    }
57}
58
59/// `PyMethodDefType` represents different types of Python callable objects.
60/// It is used by the `#[pymethods]` attribute.
61#[cfg_attr(test, derive(Clone))]
62pub enum PyMethodDefType {
63    /// Represents class method
64    Class(PyMethodDef),
65    /// Represents static method
66    Static(PyMethodDef),
67    /// Represents normal method
68    Method(PyMethodDef),
69    /// Represents class attribute, used by `#[attribute]`
70    ClassAttribute(PyClassAttributeDef),
71    /// Represents getter descriptor, used by `#[getter]`
72    Getter(PyGetterDef),
73    /// Represents setter descriptor, used by `#[setter]`
74    Setter(PySetterDef),
75    /// Represents a struct member
76    StructMember(ffi::PyMemberDef),
77}
78
79#[derive(Copy, Clone, Debug)]
80pub enum PyMethodType {
81    PyCFunction(ffi::PyCFunction),
82    PyCFunctionWithKeywords(ffi::PyCFunctionWithKeywords),
83    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
84    PyCFunctionFastWithKeywords(ffi::PyCFunctionFastWithKeywords),
85}
86
87pub type PyClassAttributeFactory = for<'p> fn(Python<'p>) -> PyResult<PyObject>;
88
89// TODO: it would be nice to use CStr in these types, but then the constructors can't be const fn
90// until `CStr::from_bytes_with_nul_unchecked` is const fn.
91
92#[derive(Clone, Debug)]
93pub struct PyMethodDef {
94    pub(crate) ml_name: &'static CStr,
95    pub(crate) ml_meth: PyMethodType,
96    pub(crate) ml_flags: c_int,
97    pub(crate) ml_doc: &'static CStr,
98}
99
100#[derive(Copy, Clone)]
101pub struct PyClassAttributeDef {
102    pub(crate) name: &'static CStr,
103    pub(crate) meth: PyClassAttributeFactory,
104}
105
106#[derive(Clone)]
107pub struct PyGetterDef {
108    pub(crate) name: &'static CStr,
109    pub(crate) meth: Getter,
110    pub(crate) doc: &'static CStr,
111}
112
113#[derive(Clone)]
114pub struct PySetterDef {
115    pub(crate) name: &'static CStr,
116    pub(crate) meth: Setter,
117    pub(crate) doc: &'static CStr,
118}
119
120unsafe impl Sync for PyMethodDef {}
121
122unsafe impl Sync for PyGetterDef {}
123
124unsafe impl Sync for PySetterDef {}
125
126impl PyMethodDef {
127    /// Define a function with no `*args` and `**kwargs`.
128    pub const fn noargs(
129        ml_name: &'static CStr,
130        cfunction: ffi::PyCFunction,
131        ml_doc: &'static CStr,
132    ) -> Self {
133        Self {
134            ml_name,
135            ml_meth: PyMethodType::PyCFunction(cfunction),
136            ml_flags: ffi::METH_NOARGS,
137            ml_doc,
138        }
139    }
140
141    /// Define a function that can take `*args` and `**kwargs`.
142    pub const fn cfunction_with_keywords(
143        ml_name: &'static CStr,
144        cfunction: ffi::PyCFunctionWithKeywords,
145        ml_doc: &'static CStr,
146    ) -> Self {
147        Self {
148            ml_name,
149            ml_meth: PyMethodType::PyCFunctionWithKeywords(cfunction),
150            ml_flags: ffi::METH_VARARGS | ffi::METH_KEYWORDS,
151            ml_doc,
152        }
153    }
154
155    /// Define a function that can take `*args` and `**kwargs`.
156    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
157    pub const fn fastcall_cfunction_with_keywords(
158        ml_name: &'static CStr,
159        cfunction: ffi::PyCFunctionFastWithKeywords,
160        ml_doc: &'static CStr,
161    ) -> Self {
162        Self {
163            ml_name,
164            ml_meth: PyMethodType::PyCFunctionFastWithKeywords(cfunction),
165            ml_flags: ffi::METH_FASTCALL | ffi::METH_KEYWORDS,
166            ml_doc,
167        }
168    }
169
170    pub const fn flags(mut self, flags: c_int) -> Self {
171        self.ml_flags |= flags;
172        self
173    }
174
175    /// Convert `PyMethodDef` to Python method definition struct `ffi::PyMethodDef`
176    pub(crate) fn as_method_def(&self) -> ffi::PyMethodDef {
177        let meth = match self.ml_meth {
178            PyMethodType::PyCFunction(meth) => ffi::PyMethodDefPointer { PyCFunction: meth },
179            PyMethodType::PyCFunctionWithKeywords(meth) => ffi::PyMethodDefPointer {
180                PyCFunctionWithKeywords: meth,
181            },
182            #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
183            PyMethodType::PyCFunctionFastWithKeywords(meth) => ffi::PyMethodDefPointer {
184                PyCFunctionFastWithKeywords: meth,
185            },
186        };
187
188        ffi::PyMethodDef {
189            ml_name: self.ml_name.as_ptr(),
190            ml_meth: meth,
191            ml_flags: self.ml_flags,
192            ml_doc: self.ml_doc.as_ptr(),
193        }
194    }
195}
196
197impl PyClassAttributeDef {
198    /// Define a class attribute.
199    pub const fn new(name: &'static CStr, meth: PyClassAttributeFactory) -> Self {
200        Self { name, meth }
201    }
202}
203
204// Manual implementation because `Python<'_>` does not implement `Debug` and
205// trait bounds on `fn` compiler-generated derive impls are too restrictive.
206impl fmt::Debug for PyClassAttributeDef {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        f.debug_struct("PyClassAttributeDef")
209            .field("name", &self.name)
210            .finish()
211    }
212}
213
214/// Class getter / setters
215pub(crate) type Getter =
216    for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject) -> PyResult<*mut ffi::PyObject>;
217pub(crate) type Setter =
218    for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject, *mut ffi::PyObject) -> PyResult<c_int>;
219
220impl PyGetterDef {
221    /// Define a getter.
222    pub const fn new(name: &'static CStr, getter: Getter, doc: &'static CStr) -> Self {
223        Self {
224            name,
225            meth: getter,
226            doc,
227        }
228    }
229}
230
231impl PySetterDef {
232    /// Define a setter.
233    pub const fn new(name: &'static CStr, setter: Setter, doc: &'static CStr) -> Self {
234        Self {
235            name,
236            meth: setter,
237            doc,
238        }
239    }
240}
241
242/// Calls an implementation of __traverse__ for tp_traverse
243///
244/// NB cannot accept `'static` visitor, this is a sanity check below:
245///
246/// ```rust,compile_fail
247/// use pyo3::prelude::*;
248/// use pyo3::pyclass::{PyTraverseError, PyVisit};
249///
250/// #[pyclass]
251/// struct Foo;
252///
253/// #[pymethods]
254/// impl Foo {
255///     fn __traverse__(&self, _visit: PyVisit<'static>) -> Result<(), PyTraverseError> {
256///         Ok(())
257///     }
258/// }
259/// ```
260///
261/// Elided lifetime should compile ok:
262///
263/// ```rust
264/// use pyo3::prelude::*;
265/// use pyo3::pyclass::{PyTraverseError, PyVisit};
266///
267/// #[pyclass]
268/// struct Foo;
269///
270/// #[pymethods]
271/// impl Foo {
272///     fn __traverse__(&self, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> {
273///         Ok(())
274///     }
275/// }
276/// ```
277#[doc(hidden)]
278pub unsafe fn _call_traverse<T>(
279    slf: *mut ffi::PyObject,
280    impl_: fn(&T, PyVisit<'_>) -> Result<(), PyTraverseError>,
281    visit: ffi::visitproc,
282    arg: *mut c_void,
283    current_traverse: ffi::traverseproc,
284) -> c_int
285where
286    T: PyClass,
287{
288    // It is important the implementation of `__traverse__` cannot safely access the GIL,
289    // c.f. https://github.com/PyO3/pyo3/issues/3165, and hence we do not expose our GIL
290    // token to the user code and lock safe methods for acquiring the GIL.
291    // (This includes enforcing the `&self` method receiver as e.g. `PyRef<Self>` could
292    // reconstruct a GIL token via `PyRef::py`.)
293    // Since we do not create a `GILPool` at all, it is important that our usage of the GIL
294    // token does not produce any owned objects thereby calling into `register_owned`.
295    let trap = PanicTrap::new("uncaught panic inside __traverse__ handler");
296    let lock = LockGIL::during_traverse();
297
298    let super_retval = call_super_traverse(slf, visit, arg, current_traverse);
299    if super_retval != 0 {
300        return super_retval;
301    }
302
303    // SAFETY: `slf` is a valid Python object pointer to a class object of type T, and
304    // traversal is running so no mutations can occur.
305    let class_object: &PyClassObject<T> = &*slf.cast();
306
307    let retval =
308    // `#[pyclass(unsendable)]` types can only be deallocated by their own thread, so
309    // do not traverse them if not on their owning thread :(
310    if class_object.check_threadsafe().is_ok()
311    // ... and we cannot traverse a type which might be being mutated by a Rust thread
312    && class_object.borrow_checker().try_borrow().is_ok() {
313        struct TraverseGuard<'a, T: PyClass>(&'a PyClassObject<T>);
314        impl<T: PyClass> Drop for TraverseGuard<'_,  T> {
315            fn drop(&mut self) {
316                self.0.borrow_checker().release_borrow()
317            }
318        }
319
320        // `.try_borrow()` above created a borrow, we need to release it when we're done
321        // traversing the object. This allows us to read `instance` safely.
322        let _guard = TraverseGuard(class_object);
323        let instance = &*class_object.contents.value.get();
324
325        let visit = PyVisit { visit, arg, _guard: PhantomData };
326
327        match catch_unwind(AssertUnwindSafe(move || impl_(instance, visit))) {
328            Ok(Ok(())) => 0,
329            Ok(Err(traverse_error)) => traverse_error.into_inner(),
330            Err(_err) => -1,
331        }
332    } else {
333        0
334    };
335
336    // Drop lock before trap just in case dropping lock panics
337    drop(lock);
338    trap.disarm();
339    retval
340}
341
342/// Call super-type traverse method, if necessary.
343///
344/// Adapted from <https://github.com/cython/cython/blob/7acfb375fb54a033f021b0982a3cd40c34fb22ac/Cython/Utility/ExtensionTypes.c#L386>
345///
346/// TODO: There are possible optimizations over looking up the base type in this way
347/// - if the base type is known in this module, can potentially look it up directly in module state
348///   (when we have it)
349/// - if the base type is a Python builtin, can jut call the C function directly
350/// - if the base type is a PyO3 type defined in the same module, can potentially do similar to
351///   tp_alloc where we solve this at compile time
352unsafe fn call_super_traverse(
353    obj: *mut ffi::PyObject,
354    visit: ffi::visitproc,
355    arg: *mut c_void,
356    current_traverse: ffi::traverseproc,
357) -> c_int {
358    // SAFETY: in this function here it's ok to work with raw type objects `ffi::Py_TYPE`
359    // because the GC is running and so
360    // - (a) we cannot do refcounting and
361    // - (b) the type of the object cannot change.
362    let mut ty = ffi::Py_TYPE(obj);
363    let mut traverse: Option<ffi::traverseproc>;
364
365    // First find the current type by the current_traverse function
366    loop {
367        traverse = get_slot(ty, TP_TRAVERSE);
368        if traverse_eq(traverse, current_traverse) {
369            break;
370        }
371        ty = get_slot(ty, TP_BASE);
372        if ty.is_null() {
373            // FIXME: return an error if current type not in the MRO? Should be impossible.
374            return 0;
375        }
376    }
377
378    // Get first base which has a different traverse function
379    while traverse_eq(traverse, current_traverse) {
380        ty = get_slot(ty, TP_BASE);
381        if ty.is_null() {
382            break;
383        }
384        traverse = get_slot(ty, TP_TRAVERSE);
385    }
386
387    // If we found a type with a different traverse function, call it
388    if let Some(traverse) = traverse {
389        return traverse(obj, visit, arg);
390    }
391
392    // FIXME same question as cython: what if the current type is not in the MRO?
393    0
394}
395
396/// Calls an implementation of __clear__ for tp_clear
397pub unsafe fn _call_clear(
398    slf: *mut ffi::PyObject,
399    impl_: for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject) -> PyResult<()>,
400    current_clear: ffi::inquiry,
401) -> c_int {
402    trampoline::trampoline(move |py| {
403        let super_retval = call_super_clear(py, slf, current_clear);
404        if super_retval != 0 {
405            return Err(PyErr::fetch(py));
406        }
407        impl_(py, slf)?;
408        Ok(0)
409    })
410}
411
412/// Call super-type traverse method, if necessary.
413///
414/// Adapted from <https://github.com/cython/cython/blob/7acfb375fb54a033f021b0982a3cd40c34fb22ac/Cython/Utility/ExtensionTypes.c#L386>
415///
416/// TODO: There are possible optimizations over looking up the base type in this way
417/// - if the base type is known in this module, can potentially look it up directly in module state
418///   (when we have it)
419/// - if the base type is a Python builtin, can jut call the C function directly
420/// - if the base type is a PyO3 type defined in the same module, can potentially do similar to
421///   tp_alloc where we solve this at compile time
422unsafe fn call_super_clear(
423    py: Python<'_>,
424    obj: *mut ffi::PyObject,
425    current_clear: ffi::inquiry,
426) -> c_int {
427    let mut ty = PyType::from_borrowed_type_ptr(py, ffi::Py_TYPE(obj));
428    let mut clear: Option<ffi::inquiry>;
429
430    // First find the current type by the current_clear function
431    loop {
432        clear = ty.get_slot(TP_CLEAR);
433        if clear_eq(clear, current_clear) {
434            break;
435        }
436        let base = ty.get_slot(TP_BASE);
437        if base.is_null() {
438            // FIXME: return an error if current type not in the MRO? Should be impossible.
439            return 0;
440        }
441        ty = PyType::from_borrowed_type_ptr(py, base);
442    }
443
444    // Get first base which has a different clear function
445    while clear_eq(clear, current_clear) {
446        let base = ty.get_slot(TP_BASE);
447        if base.is_null() {
448            break;
449        }
450        ty = PyType::from_borrowed_type_ptr(py, base);
451        clear = ty.get_slot(TP_CLEAR);
452    }
453
454    // If we found a type with a different clear function, call it
455    if let Some(clear) = clear {
456        return clear(obj);
457    }
458
459    // FIXME same question as cython: what if the current type is not in the MRO?
460    0
461}
462
463// Autoref-based specialization for handling `__next__` returning `Option`
464
465pub struct IterBaseTag;
466
467impl IterBaseTag {
468    #[inline]
469    pub fn convert<'py, Value, Target>(self, py: Python<'py>, value: Value) -> PyResult<Target>
470    where
471        Value: IntoPyCallbackOutput<'py, Target>,
472    {
473        value.convert(py)
474    }
475}
476
477pub trait IterBaseKind {
478    #[inline]
479    fn iter_tag(&self) -> IterBaseTag {
480        IterBaseTag
481    }
482}
483
484impl<Value> IterBaseKind for &Value {}
485
486pub struct IterOptionTag;
487
488impl IterOptionTag {
489    #[inline]
490    pub fn convert<'py, Value>(
491        self,
492        py: Python<'py>,
493        value: Option<Value>,
494    ) -> PyResult<*mut ffi::PyObject>
495    where
496        Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
497    {
498        match value {
499            Some(value) => value.convert(py),
500            None => Ok(null_mut()),
501        }
502    }
503}
504
505pub trait IterOptionKind {
506    #[inline]
507    fn iter_tag(&self) -> IterOptionTag {
508        IterOptionTag
509    }
510}
511
512impl<Value> IterOptionKind for Option<Value> {}
513
514pub struct IterResultOptionTag;
515
516impl IterResultOptionTag {
517    #[inline]
518    pub fn convert<'py, Value, Error>(
519        self,
520        py: Python<'py>,
521        value: Result<Option<Value>, Error>,
522    ) -> PyResult<*mut ffi::PyObject>
523    where
524        Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
525        Error: Into<PyErr>,
526    {
527        match value {
528            Ok(Some(value)) => value.convert(py),
529            Ok(None) => Ok(null_mut()),
530            Err(err) => Err(err.into()),
531        }
532    }
533}
534
535pub trait IterResultOptionKind {
536    #[inline]
537    fn iter_tag(&self) -> IterResultOptionTag {
538        IterResultOptionTag
539    }
540}
541
542impl<Value, Error> IterResultOptionKind for Result<Option<Value>, Error> {}
543
544// Autoref-based specialization for handling `__anext__` returning `Option`
545
546pub struct AsyncIterBaseTag;
547
548impl AsyncIterBaseTag {
549    #[inline]
550    pub fn convert<'py, Value, Target>(self, py: Python<'py>, value: Value) -> PyResult<Target>
551    where
552        Value: IntoPyCallbackOutput<'py, Target>,
553    {
554        value.convert(py)
555    }
556}
557
558pub trait AsyncIterBaseKind {
559    #[inline]
560    fn async_iter_tag(&self) -> AsyncIterBaseTag {
561        AsyncIterBaseTag
562    }
563}
564
565impl<Value> AsyncIterBaseKind for &Value {}
566
567pub struct AsyncIterOptionTag;
568
569impl AsyncIterOptionTag {
570    #[inline]
571    pub fn convert<'py, Value>(
572        self,
573        py: Python<'py>,
574        value: Option<Value>,
575    ) -> PyResult<*mut ffi::PyObject>
576    where
577        Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
578    {
579        match value {
580            Some(value) => value.convert(py),
581            None => Err(PyStopAsyncIteration::new_err(())),
582        }
583    }
584}
585
586pub trait AsyncIterOptionKind {
587    #[inline]
588    fn async_iter_tag(&self) -> AsyncIterOptionTag {
589        AsyncIterOptionTag
590    }
591}
592
593impl<Value> AsyncIterOptionKind for Option<Value> {}
594
595pub struct AsyncIterResultOptionTag;
596
597impl AsyncIterResultOptionTag {
598    #[inline]
599    pub fn convert<'py, Value, Error>(
600        self,
601        py: Python<'py>,
602        value: Result<Option<Value>, Error>,
603    ) -> PyResult<*mut ffi::PyObject>
604    where
605        Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
606        Error: Into<PyErr>,
607    {
608        match value {
609            Ok(Some(value)) => value.convert(py),
610            Ok(None) => Err(PyStopAsyncIteration::new_err(())),
611            Err(err) => Err(err.into()),
612        }
613    }
614}
615
616pub trait AsyncIterResultOptionKind {
617    #[inline]
618    fn async_iter_tag(&self) -> AsyncIterResultOptionTag {
619        AsyncIterResultOptionTag
620    }
621}
622
623impl<Value, Error> AsyncIterResultOptionKind for Result<Option<Value>, Error> {}
624
625/// Used in `#[classmethod]` to pass the class object to the method
626/// and also in `#[pyfunction(pass_module)]`.
627///
628/// This is a wrapper to avoid implementing `From<Bound>` for GIL Refs.
629///
630/// Once the GIL Ref API is fully removed, it should be possible to simplify
631/// this to just `&'a Bound<'py, T>` and `From` implementations.
632pub struct BoundRef<'a, 'py, T>(pub &'a Bound<'py, T>);
633
634impl<'a, 'py> BoundRef<'a, 'py, PyAny> {
635    pub unsafe fn ref_from_ptr(py: Python<'py>, ptr: &'a *mut ffi::PyObject) -> Self {
636        BoundRef(Bound::ref_from_ptr(py, ptr))
637    }
638
639    pub unsafe fn ref_from_ptr_or_opt(
640        py: Python<'py>,
641        ptr: &'a *mut ffi::PyObject,
642    ) -> Option<Self> {
643        Bound::ref_from_ptr_or_opt(py, ptr).as_ref().map(BoundRef)
644    }
645
646    pub fn downcast<T: PyTypeCheck>(self) -> Result<BoundRef<'a, 'py, T>, DowncastError<'a, 'py>> {
647        self.0.downcast::<T>().map(BoundRef)
648    }
649
650    pub unsafe fn downcast_unchecked<T>(self) -> BoundRef<'a, 'py, T> {
651        BoundRef(self.0.downcast_unchecked::<T>())
652    }
653}
654
655impl<'a, 'py, T: PyClass> TryFrom<BoundRef<'a, 'py, T>> for PyRef<'py, T> {
656    type Error = PyBorrowError;
657    #[inline]
658    fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
659        value.0.try_borrow()
660    }
661}
662
663impl<'a, 'py, T: PyClass<Frozen = False>> TryFrom<BoundRef<'a, 'py, T>> for PyRefMut<'py, T> {
664    type Error = PyBorrowMutError;
665    #[inline]
666    fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
667        value.0.try_borrow_mut()
668    }
669}
670
671impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for Bound<'py, T> {
672    #[inline]
673    fn from(bound: BoundRef<'a, 'py, T>) -> Self {
674        bound.0.clone()
675    }
676}
677
678impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for &'a Bound<'py, T> {
679    #[inline]
680    fn from(bound: BoundRef<'a, 'py, T>) -> Self {
681        bound.0
682    }
683}
684
685impl<T> From<BoundRef<'_, '_, T>> for Py<T> {
686    #[inline]
687    fn from(bound: BoundRef<'_, '_, T>) -> Self {
688        bound.0.clone().unbind()
689    }
690}
691
692impl<'py, T> std::ops::Deref for BoundRef<'_, 'py, T> {
693    type Target = Bound<'py, T>;
694    #[inline]
695    fn deref(&self) -> &Self::Target {
696        self.0
697    }
698}
699
700pub unsafe fn tp_new_impl<T: PyClass>(
701    py: Python<'_>,
702    initializer: PyClassInitializer<T>,
703    target_type: *mut ffi::PyTypeObject,
704) -> PyResult<*mut ffi::PyObject> {
705    initializer
706        .create_class_object_of_type(py, target_type)
707        .map(Bound::into_ptr)
708}
709
710#[cfg(test)]
711mod tests {
712    #[test]
713    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
714    fn test_fastcall_function_with_keywords() {
715        use super::PyMethodDef;
716        use crate::types::{PyAnyMethods, PyCFunction};
717        use crate::{ffi, Python};
718
719        Python::with_gil(|py| {
720            unsafe extern "C" fn accepts_no_arguments(
721                _slf: *mut ffi::PyObject,
722                _args: *const *mut ffi::PyObject,
723                nargs: ffi::Py_ssize_t,
724                kwargs: *mut ffi::PyObject,
725            ) -> *mut ffi::PyObject {
726                assert_eq!(nargs, 0);
727                assert!(kwargs.is_null());
728                Python::assume_gil_acquired().None().into_ptr()
729            }
730
731            let f = PyCFunction::internal_new(
732                py,
733                &PyMethodDef::fastcall_cfunction_with_keywords(
734                    ffi::c_str!("test"),
735                    accepts_no_arguments,
736                    ffi::c_str!("doc"),
737                ),
738                None,
739            )
740            .unwrap();
741
742            f.call0().unwrap();
743        });
744    }
745}