11//! Contains initialization utilities for `#[pyclass]`.
22use crate :: ffi_ptr_ext:: FfiPtrExt ;
3- use crate :: internal:: get_slot:: TP_ALLOC ;
4- use crate :: types:: PyType ;
5- use crate :: { ffi, Borrowed , PyErr , PyResult , Python } ;
3+ use crate :: internal:: get_slot:: TP_NEW ;
4+ use crate :: types:: { PyDict , PyTuple , PyType } ;
5+ use crate :: { ffi, Borrowed , Bound , PyErr , PyResult , Python } ;
66use crate :: { ffi:: PyTypeObject , sealed:: Sealed , type_object:: PyTypeInfo } ;
77use std:: marker:: PhantomData ;
88
9+ use super :: pyclass:: PyClassBaseType ;
10+
911/// Initializer for Python types.
1012///
1113/// This trait is intended to use internally for distinguishing `#[pyclass]` and
@@ -17,69 +19,70 @@ pub trait PyObjectInit<T>: Sized + Sealed {
1719 self ,
1820 py : Python < ' _ > ,
1921 subtype : * mut PyTypeObject ,
22+ args : & Bound < ' _ , PyTuple > ,
23+ kwargs : Option < & Bound < ' _ , PyDict > > ,
2024 ) -> PyResult < * mut ffi:: PyObject > ;
2125
2226 #[ doc( hidden) ]
2327 fn can_be_subclassed ( & self ) -> bool ;
2428}
2529
26- /// Initializer for Python native types, like ` PyDict` .
27- pub struct PyNativeTypeInitializer < T : PyTypeInfo > ( pub PhantomData < T > ) ;
30+ /// Initializer for Python native types, like [ PyDict] .
31+ pub struct PyNativeTypeInitializer < T : PyTypeInfo + PyClassBaseType > ( pub PhantomData < T > ) ;
2832
29- impl < T : PyTypeInfo > PyObjectInit < T > for PyNativeTypeInitializer < T > {
33+ impl < T : PyTypeInfo + PyClassBaseType > PyObjectInit < T > for PyNativeTypeInitializer < T > {
34+ /// call `__new__` ([ffi::PyTypeObject::tp_new]) for the native base type.
35+ /// This will allocate a new python object and initialize the part relating to the native base type.
3036 unsafe fn into_new_object (
3137 self ,
3238 py : Python < ' _ > ,
3339 subtype : * mut PyTypeObject ,
40+ args : & Bound < ' _ , PyTuple > ,
41+ kwargs : Option < & Bound < ' _ , PyDict > > ,
3442 ) -> PyResult < * mut ffi:: PyObject > {
3543 unsafe fn inner (
3644 py : Python < ' _ > ,
37- type_object : * mut PyTypeObject ,
45+ native_base_type : * mut PyTypeObject ,
3846 subtype : * mut PyTypeObject ,
47+ args : & Bound < ' _ , PyTuple > ,
48+ kwargs : Option < & Bound < ' _ , PyDict > > ,
49+ new_accepts_arguments : bool ,
3950 ) -> PyResult < * mut ffi:: PyObject > {
40- // HACK (due to FIXME below): PyBaseObject_Type's tp_new isn't happy with NULL arguments
41- let is_base_object = type_object == std:: ptr:: addr_of_mut!( ffi:: PyBaseObject_Type ) ;
42- let subtype_borrowed: Borrowed < ' _ , ' _ , PyType > = subtype
51+ let native_base_type_borrowed: Borrowed < ' _ , ' _ , PyType > = native_base_type
4352 . cast :: < ffi:: PyObject > ( )
4453 . assume_borrowed_unchecked ( py)
4554 . downcast_unchecked ( ) ;
55+ let tp_new = native_base_type_borrowed
56+ . get_slot ( TP_NEW )
57+ . unwrap_or ( ffi:: PyType_GenericNew ) ;
4658
47- if is_base_object {
48- let alloc = subtype_borrowed
49- . get_slot ( TP_ALLOC )
50- . unwrap_or ( ffi:: PyType_GenericAlloc ) ;
51-
52- let obj = alloc ( subtype, 0 ) ;
53- return if obj. is_null ( ) {
54- Err ( PyErr :: fetch ( py) )
55- } else {
56- Ok ( obj)
57- } ;
58- }
59-
60- #[ cfg( Py_LIMITED_API ) ]
61- unreachable ! ( "subclassing native types is not possible with the `abi3` feature" ) ;
59+ let obj = if new_accepts_arguments {
60+ tp_new (
61+ subtype,
62+ args. as_ptr ( ) ,
63+ kwargs
64+ . map ( |obj| obj. as_ptr ( ) )
65+ . unwrap_or ( std:: ptr:: null_mut ( ) ) ,
66+ )
67+ } else {
68+ let args = PyTuple :: empty ( py) ;
69+ tp_new ( subtype, args. as_ptr ( ) , std:: ptr:: null_mut ( ) )
70+ } ;
6271
63- #[ cfg( not( Py_LIMITED_API ) ) ]
64- {
65- match ( * type_object) . tp_new {
66- // FIXME: Call __new__ with actual arguments
67- Some ( newfunc) => {
68- let obj = newfunc ( subtype, std:: ptr:: null_mut ( ) , std:: ptr:: null_mut ( ) ) ;
69- if obj. is_null ( ) {
70- Err ( PyErr :: fetch ( py) )
71- } else {
72- Ok ( obj)
73- }
74- }
75- None => Err ( crate :: exceptions:: PyTypeError :: new_err (
76- "base type without tp_new" ,
77- ) ) ,
78- }
72+ if obj. is_null ( ) {
73+ Err ( PyErr :: fetch ( py) )
74+ } else {
75+ Ok ( obj)
7976 }
8077 }
81- let type_object = T :: type_object_raw ( py) ;
82- inner ( py, type_object, subtype)
78+ inner (
79+ py,
80+ T :: type_object_raw ( py) ,
81+ subtype,
82+ args,
83+ kwargs,
84+ T :: NEW_ACCEPTS_ARGUMENTS ,
85+ )
8386 }
8487
8588 #[ inline]
0 commit comments