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&mut DebugStruct<'_, '_>.debug_struct("PyClassAttributeDef")
209 .field(name:"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 = unsafe { 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> = unsafe { &*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 = unsafe {&*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 = unsafe { 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 = unsafe { get_slot(ty, TP_TRAVERSE) };
368 if traverse_eq(traverse, current_traverse) {
369 break;
370 }
371 ty = unsafe { 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 = unsafe { get_slot(ty, TP_BASE) };
381 if ty.is_null() {
382 break;
383 }
384 traverse = unsafe { 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 unsafe { 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 unsafe {
403 trampoline::trampoline(body:move |py: Python<'_>| {
404 let super_retval = call_super_clear(py, obj:slf, current_clear);
405 if super_retval != 0 {
406 return Err(PyErr::fetch(py));
407 }
408 impl_(py, slf)?;
409 Ok(0)
410 })
411 }
412}
413
414/// Call super-type traverse method, if necessary.
415///
416/// Adapted from <https://github.com/cython/cython/blob/7acfb375fb54a033f021b0982a3cd40c34fb22ac/Cython/Utility/ExtensionTypes.c#L386>
417///
418/// TODO: There are possible optimizations over looking up the base type in this way
419/// - if the base type is known in this module, can potentially look it up directly in module state
420/// (when we have it)
421/// - if the base type is a Python builtin, can jut call the C function directly
422/// - if the base type is a PyO3 type defined in the same module, can potentially do similar to
423/// tp_alloc where we solve this at compile time
424unsafe fn call_super_clear(
425 py: Python<'_>,
426 obj: *mut ffi::PyObject,
427 current_clear: ffi::inquiry,
428) -> c_int {
429 let mut ty = unsafe { PyType::from_borrowed_type_ptr(py, ffi::Py_TYPE(obj)) };
430 let mut clear: Option<ffi::inquiry>;
431
432 // First find the current type by the current_clear function
433 loop {
434 clear = ty.get_slot(TP_CLEAR);
435 if clear_eq(clear, current_clear) {
436 break;
437 }
438 let base = ty.get_slot(TP_BASE);
439 if base.is_null() {
440 // FIXME: return an error if current type not in the MRO? Should be impossible.
441 return 0;
442 }
443 ty = unsafe { PyType::from_borrowed_type_ptr(py, base) };
444 }
445
446 // Get first base which has a different clear function
447 while clear_eq(clear, current_clear) {
448 let base = ty.get_slot(TP_BASE);
449 if base.is_null() {
450 break;
451 }
452 ty = unsafe { PyType::from_borrowed_type_ptr(py, base) };
453 clear = ty.get_slot(TP_CLEAR);
454 }
455
456 // If we found a type with a different clear function, call it
457 if let Some(clear) = clear {
458 return unsafe { clear(obj) };
459 }
460
461 // FIXME same question as cython: what if the current type is not in the MRO?
462 0
463}
464
465// Autoref-based specialization for handling `__next__` returning `Option`
466
467pub struct IterBaseTag;
468
469impl IterBaseTag {
470 #[inline]
471 pub fn convert<'py, Value, Target>(self, py: Python<'py>, value: Value) -> PyResult<Target>
472 where
473 Value: IntoPyCallbackOutput<'py, Target>,
474 {
475 value.convert(py)
476 }
477}
478
479pub trait IterBaseKind {
480 #[inline]
481 fn iter_tag(&self) -> IterBaseTag {
482 IterBaseTag
483 }
484}
485
486impl<Value> IterBaseKind for &Value {}
487
488pub struct IterOptionTag;
489
490impl IterOptionTag {
491 #[inline]
492 pub fn convert<'py, Value>(
493 self,
494 py: Python<'py>,
495 value: Option<Value>,
496 ) -> PyResult<*mut ffi::PyObject>
497 where
498 Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
499 {
500 match value {
501 Some(value: Value) => value.convert(py),
502 None => Ok(null_mut()),
503 }
504 }
505}
506
507pub trait IterOptionKind {
508 #[inline]
509 fn iter_tag(&self) -> IterOptionTag {
510 IterOptionTag
511 }
512}
513
514impl<Value> IterOptionKind for Option<Value> {}
515
516pub struct IterResultOptionTag;
517
518impl IterResultOptionTag {
519 #[inline]
520 pub fn convert<'py, Value, Error>(
521 self,
522 py: Python<'py>,
523 value: Result<Option<Value>, Error>,
524 ) -> PyResult<*mut ffi::PyObject>
525 where
526 Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
527 Error: Into<PyErr>,
528 {
529 match value {
530 Ok(Some(value: Value)) => value.convert(py),
531 Ok(None) => Ok(null_mut()),
532 Err(err: Error) => Err(err.into()),
533 }
534 }
535}
536
537pub trait IterResultOptionKind {
538 #[inline]
539 fn iter_tag(&self) -> IterResultOptionTag {
540 IterResultOptionTag
541 }
542}
543
544impl<Value, Error> IterResultOptionKind for Result<Option<Value>, Error> {}
545
546// Autoref-based specialization for handling `__anext__` returning `Option`
547
548pub struct AsyncIterBaseTag;
549
550impl AsyncIterBaseTag {
551 #[inline]
552 pub fn convert<'py, Value, Target>(self, py: Python<'py>, value: Value) -> PyResult<Target>
553 where
554 Value: IntoPyCallbackOutput<'py, Target>,
555 {
556 value.convert(py)
557 }
558}
559
560pub trait AsyncIterBaseKind {
561 #[inline]
562 fn async_iter_tag(&self) -> AsyncIterBaseTag {
563 AsyncIterBaseTag
564 }
565}
566
567impl<Value> AsyncIterBaseKind for &Value {}
568
569pub struct AsyncIterOptionTag;
570
571impl AsyncIterOptionTag {
572 #[inline]
573 pub fn convert<'py, Value>(
574 self,
575 py: Python<'py>,
576 value: Option<Value>,
577 ) -> PyResult<*mut ffi::PyObject>
578 where
579 Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
580 {
581 match value {
582 Some(value: Value) => value.convert(py),
583 None => Err(PyStopAsyncIteration::new_err(())),
584 }
585 }
586}
587
588pub trait AsyncIterOptionKind {
589 #[inline]
590 fn async_iter_tag(&self) -> AsyncIterOptionTag {
591 AsyncIterOptionTag
592 }
593}
594
595impl<Value> AsyncIterOptionKind for Option<Value> {}
596
597pub struct AsyncIterResultOptionTag;
598
599impl AsyncIterResultOptionTag {
600 #[inline]
601 pub fn convert<'py, Value, Error>(
602 self,
603 py: Python<'py>,
604 value: Result<Option<Value>, Error>,
605 ) -> PyResult<*mut ffi::PyObject>
606 where
607 Value: IntoPyCallbackOutput<'py, *mut ffi::PyObject>,
608 Error: Into<PyErr>,
609 {
610 match value {
611 Ok(Some(value: Value)) => value.convert(py),
612 Ok(None) => Err(PyStopAsyncIteration::new_err(())),
613 Err(err: Error) => Err(err.into()),
614 }
615 }
616}
617
618pub trait AsyncIterResultOptionKind {
619 #[inline]
620 fn async_iter_tag(&self) -> AsyncIterResultOptionTag {
621 AsyncIterResultOptionTag
622 }
623}
624
625impl<Value, Error> AsyncIterResultOptionKind for Result<Option<Value>, Error> {}
626
627/// Used in `#[classmethod]` to pass the class object to the method
628/// and also in `#[pyfunction(pass_module)]`.
629///
630/// This is a wrapper to avoid implementing `From<Bound>` for GIL Refs.
631///
632/// Once the GIL Ref API is fully removed, it should be possible to simplify
633/// this to just `&'a Bound<'py, T>` and `From` implementations.
634pub struct BoundRef<'a, 'py, T>(pub &'a Bound<'py, T>);
635
636impl<'a, 'py> BoundRef<'a, 'py, PyAny> {
637 pub unsafe fn ref_from_ptr(py: Python<'py>, ptr: &'a *mut ffi::PyObject) -> Self {
638 unsafe { BoundRef(Bound::ref_from_ptr(py, ptr)) }
639 }
640
641 pub unsafe fn ref_from_ptr_or_opt(
642 py: Python<'py>,
643 ptr: &'a *mut ffi::PyObject,
644 ) -> Option<Self> {
645 unsafe { Bound::ref_from_ptr_or_opt(py, ptr).as_ref().map(BoundRef) }
646 }
647
648 pub fn downcast<T: PyTypeCheck>(self) -> Result<BoundRef<'a, 'py, T>, DowncastError<'a, 'py>> {
649 self.0.downcast::<T>().map(op:BoundRef)
650 }
651
652 pub unsafe fn downcast_unchecked<T>(self) -> BoundRef<'a, 'py, T> {
653 unsafe { BoundRef(self.0.downcast_unchecked::<T>()) }
654 }
655}
656
657impl<'a, 'py, T: PyClass> TryFrom<BoundRef<'a, 'py, T>> for PyRef<'py, T> {
658 type Error = PyBorrowError;
659 #[inline]
660 fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
661 value.0.try_borrow()
662 }
663}
664
665impl<'a, 'py, T: PyClass<Frozen = False>> TryFrom<BoundRef<'a, 'py, T>> for PyRefMut<'py, T> {
666 type Error = PyBorrowMutError;
667 #[inline]
668 fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
669 value.0.try_borrow_mut()
670 }
671}
672
673impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for Bound<'py, T> {
674 #[inline]
675 fn from(bound: BoundRef<'a, 'py, T>) -> Self {
676 bound.0.clone()
677 }
678}
679
680impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for &'a Bound<'py, T> {
681 #[inline]
682 fn from(bound: BoundRef<'a, 'py, T>) -> Self {
683 bound.0
684 }
685}
686
687impl<T> From<BoundRef<'_, '_, T>> for Py<T> {
688 #[inline]
689 fn from(bound: BoundRef<'_, '_, T>) -> Self {
690 bound.0.clone().unbind()
691 }
692}
693
694impl<'py, T> std::ops::Deref for BoundRef<'_, 'py, T> {
695 type Target = Bound<'py, T>;
696 #[inline]
697 fn deref(&self) -> &Self::Target {
698 self.0
699 }
700}
701
702pub unsafe fn tp_new_impl<T: PyClass>(
703 py: Python<'_>,
704 initializer: PyClassInitializer<T>,
705 target_type: *mut ffi::PyTypeObject,
706) -> PyResult<*mut ffi::PyObject> {
707 unsafe {
708 initializer
709 .create_class_object_of_type(py, target_type)
710 .map(op:Bound::into_ptr)
711 }
712}
713
714#[cfg(test)]
715mod tests {
716 #[test]
717 #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
718 fn test_fastcall_function_with_keywords() {
719 use super::PyMethodDef;
720 use crate::types::{PyAnyMethods, PyCFunction};
721 use crate::{ffi, Python};
722
723 Python::with_gil(|py| {
724 unsafe extern "C" fn accepts_no_arguments(
725 _slf: *mut ffi::PyObject,
726 _args: *const *mut ffi::PyObject,
727 nargs: ffi::Py_ssize_t,
728 kwargs: *mut ffi::PyObject,
729 ) -> *mut ffi::PyObject {
730 assert_eq!(nargs, 0);
731 assert!(kwargs.is_null());
732 unsafe { Python::assume_gil_acquired().None().into_ptr() }
733 }
734
735 let f = PyCFunction::internal_new(
736 py,
737 &PyMethodDef::fastcall_cfunction_with_keywords(
738 ffi::c_str!("test"),
739 accepts_no_arguments,
740 ffi::c_str!("doc"),
741 ),
742 None,
743 )
744 .unwrap();
745
746 f.call0().unwrap();
747 });
748 }
749}
750