@@ -9,7 +9,7 @@ use crate::types::PyAny;
9
9
use crate :: { class, ffi, PyCell , PyErr , PyNativeType , PyResult , PyTypeInfo , Python } ;
10
10
use std:: ffi:: CString ;
11
11
use std:: marker:: PhantomData ;
12
- use std:: os:: raw:: c_void;
12
+ use std:: os:: raw:: { c_int , c_void} ;
13
13
use std:: { ptr, thread} ;
14
14
15
15
#[ inline]
@@ -107,120 +107,134 @@ pub trait PyClass:
107
107
type BaseNativeType : PyTypeInfo + PyNativeType ;
108
108
}
109
109
110
- #[ cfg( not( Py_LIMITED_API ) ) ]
111
- pub ( crate ) fn initialize_type_object < T > (
110
+ pub ( crate ) fn maybe_push_slot (
111
+ slots : & mut Vec < ffi:: PyType_Slot > ,
112
+ slot : c_int ,
113
+ val : Option < * mut c_void > ,
114
+ ) {
115
+ if let Some ( v) = val {
116
+ slots. push ( ffi:: PyType_Slot {
117
+ slot : slot,
118
+ pfunc : v,
119
+ } ) ;
120
+ }
121
+ }
122
+
123
+ pub ( crate ) fn create_type_object < T > (
112
124
py : Python ,
113
125
module_name : Option < & str > ,
114
- type_object : & mut ffi:: PyTypeObject ,
115
- ) -> PyResult < ( ) >
126
+ ) -> PyResult < * mut ffi:: PyTypeObject >
116
127
where
117
128
T : PyClass ,
118
129
{
119
- type_object. tp_doc = match T :: DESCRIPTION {
120
- // PyPy will segfault if passed only a nul terminator as `tp_doc`, ptr::null() is OK though.
121
- "\0 " => ptr:: null ( ) ,
122
- s if s. as_bytes ( ) . ends_with ( b"\0 " ) => s. as_ptr ( ) as _ ,
123
- // If the description is not null-terminated, create CString and leak it
124
- s => CString :: new ( s) ?. into_raw ( ) ,
125
- } ;
126
-
127
- type_object. tp_base = T :: BaseType :: type_object_raw ( py) ;
128
-
129
- type_object. tp_name = match module_name {
130
- Some ( module_name) => CString :: new ( format ! ( "{}.{}" , module_name, T :: NAME ) ) ?. into_raw ( ) ,
131
- None => CString :: new ( T :: NAME ) ?. into_raw ( ) ,
132
- } ;
133
-
134
- // dealloc
135
- type_object. tp_dealloc = tp_dealloc :: < T > ( ) ;
136
-
137
- // type size
138
- type_object. tp_basicsize = std:: mem:: size_of :: < T :: Layout > ( ) as ffi:: Py_ssize_t ;
139
-
140
- // __dict__ support
141
- if let Some ( dict_offset) = PyCell :: < T > :: dict_offset ( ) {
142
- type_object. tp_dictoffset = dict_offset as ffi:: Py_ssize_t ;
143
- }
144
-
145
- // weakref support
146
- if let Some ( weakref_offset) = PyCell :: < T > :: weakref_offset ( ) {
147
- type_object. tp_weaklistoffset = weakref_offset as ffi:: Py_ssize_t ;
148
- }
149
-
150
- // GC support
151
- if let Some ( gc) = T :: gc_methods ( ) {
152
- unsafe { gc. as_ref ( ) } . update_typeobj ( type_object) ;
153
- }
154
-
155
- // descriptor protocol
156
- if let Some ( descr) = T :: descr_methods ( ) {
157
- unsafe { descr. as_ref ( ) } . update_typeobj ( type_object) ;
158
- }
159
-
160
- // iterator methods
161
- if let Some ( iter) = T :: iter_methods ( ) {
162
- unsafe { iter. as_ref ( ) } . update_typeobj ( type_object) ;
163
- }
164
-
165
- // nb_bool is a part of PyObjectProtocol, but should be placed under tp_as_number
166
- let mut nb_bool = None ;
167
- // basic methods
130
+ let mut slots = vec ! [ ] ;
168
131
if let Some ( basic) = T :: basic_methods ( ) {
169
- unsafe { basic. as_ref ( ) } . update_typeobj ( type_object) ;
170
- nb_bool = unsafe { basic. as_ref ( ) } . nb_bool ;
132
+ unsafe { basic. as_ref ( ) } . update_slots ( & mut slots) ;
171
133
}
172
134
173
- // number methods
174
- type_object. tp_as_number = T :: number_methods ( )
175
- . map ( |mut p| {
176
- unsafe { p. as_mut ( ) } . nb_bool = nb_bool;
177
- p. as_ptr ( )
178
- } )
179
- . unwrap_or_else ( || nb_bool. map_or_else ( ptr:: null_mut, ffi:: PyNumberMethods :: from_nb_bool) ) ;
180
- // mapping methods
181
- type_object. tp_as_mapping = T :: mapping_methods ( ) . map_or_else ( ptr:: null_mut, |p| p. as_ptr ( ) ) ;
182
- // sequence methods
183
- type_object. tp_as_sequence = T :: sequence_methods ( ) . map_or_else ( ptr:: null_mut, |p| p. as_ptr ( ) ) ;
184
- // async methods
185
- type_object. tp_as_async = T :: async_methods ( ) . map_or_else ( ptr:: null_mut, |p| p. as_ptr ( ) ) ;
186
- // buffer protocol
187
- type_object. tp_as_buffer = T :: buffer_methods ( ) . map_or_else ( ptr:: null_mut, |p| p. as_ptr ( ) ) ;
188
-
189
- let ( new, call, mut methods) = py_class_method_defs :: < T > ( ) ;
190
-
191
- // normal methods
192
- if !methods. is_empty ( ) {
193
- methods. push ( ffi:: PyMethodDef_INIT ) ;
194
- type_object. tp_methods = Box :: into_raw ( methods. into_boxed_slice ( ) ) as _ ;
135
+ if let Some ( number) = T :: number_methods ( ) {
136
+ maybe_push_slot (
137
+ & mut slots,
138
+ ffi:: Py_nb_add ,
139
+ unsafe { number. as_ref ( ) } . nb_add . map ( |v| v as * mut c_void ) ,
140
+ ) ;
195
141
}
196
142
197
- // __new__ method
198
- type_object. tp_new = new;
199
- // __call__ method
200
- type_object. tp_call = call;
201
-
202
- // properties
203
- let mut props = py_class_properties :: < T > ( ) ;
143
+ slots. push ( ffi:: PyType_Slot {
144
+ slot : 0 ,
145
+ pfunc : ptr:: null_mut ( ) ,
146
+ } ) ;
147
+ let mut spec = ffi:: PyType_Spec {
148
+ name : match module_name {
149
+ Some ( module_name) => CString :: new ( format ! ( "{}.{}" , module_name, T :: NAME ) ) ?. into_raw ( ) ,
150
+ None => CString :: new ( T :: NAME ) ?. into_raw ( ) ,
151
+ } ,
152
+ basicsize : std:: mem:: size_of :: < T :: Layout > ( ) as c_int ,
153
+ itemsize : 0 ,
154
+ flags : 0 , // XXXX: FILL ME IN PROPERLY,
155
+ slots : slots. as_mut_slice ( ) . as_mut_ptr ( ) ,
156
+ } ;
204
157
205
- if !T :: Dict :: IS_DUMMY {
206
- props. push ( ffi:: PyGetSetDef_DICT ) ;
207
- }
208
- if !props. is_empty ( ) {
209
- props. push ( ffi:: PyGetSetDef_INIT ) ;
210
- type_object. tp_getset = Box :: into_raw ( props. into_boxed_slice ( ) ) as _ ;
158
+ let type_object = unsafe { ffi:: PyType_FromSpec ( & mut spec) } ;
159
+ if type_object. is_null ( ) {
160
+ PyErr :: fetch ( py) . into ( )
161
+ } else {
162
+ Ok ( type_object as * mut ffi:: PyTypeObject )
211
163
}
212
164
213
- // set type flags
214
- py_class_flags :: < T > ( type_object) ;
215
-
216
- // register type object
217
- unsafe {
218
- if ffi:: PyType_Ready ( type_object) == 0 {
219
- Ok ( ( ) )
220
- } else {
221
- PyErr :: fetch ( py) . into ( )
222
- }
223
- }
165
+ // type_object.tp_doc = match T::DESCRIPTION {
166
+ // // PyPy will segfault if passed only a nul terminator as `tp_doc`, ptr::null() is OK though.
167
+ // "\0" => ptr::null(),
168
+ // s if s.as_bytes().ends_with(b"\0") => s.as_ptr() as _,
169
+ // // If the description is not null-terminated, create CString and leak it
170
+ // s => CString::new(s)?.into_raw(),
171
+ // };
172
+
173
+ // type_object.tp_base = T::BaseType::type_object_raw(py);
174
+
175
+ // // dealloc
176
+ // type_object.tp_dealloc = tp_dealloc::<T>();
177
+
178
+ // // __dict__ support
179
+ // if let Some(dict_offset) = PyCell::<T>::dict_offset() {
180
+ // type_object.tp_dictoffset = dict_offset as ffi::Py_ssize_t;
181
+ // }
182
+
183
+ // // weakref support
184
+ // if let Some(weakref_offset) = PyCell::<T>::weakref_offset() {
185
+ // type_object.tp_weaklistoffset = weakref_offset as ffi::Py_ssize_t;
186
+ // }
187
+
188
+ // // GC support
189
+ // if let Some(gc) = T::gc_methods() {
190
+ // unsafe { gc.as_ref() }.update_typeobj(type_object);
191
+ // }
192
+
193
+ // // descriptor protocol
194
+ // if let Some(descr) = T::descr_methods() {
195
+ // unsafe { descr.as_ref() }.update_typeobj(type_object);
196
+ // }
197
+
198
+ // // iterator methods
199
+ // if let Some(iter) = T::iter_methods() {
200
+ // unsafe { iter.as_ref() }.update_typeobj(type_object);
201
+ // }
202
+
203
+ // // mapping methods
204
+ // type_object.tp_as_mapping = T::mapping_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
205
+ // // sequence methods
206
+ // type_object.tp_as_sequence = T::sequence_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
207
+ // // async methods
208
+ // type_object.tp_as_async = T::async_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
209
+ // // buffer protocol
210
+ // type_object.tp_as_buffer = T::buffer_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
211
+
212
+ // let (new, call, mut methods) = py_class_method_defs::<T>();
213
+
214
+ // // normal methods
215
+ // if !methods.is_empty() {
216
+ // methods.push(ffi::PyMethodDef_INIT);
217
+ // type_object.tp_methods = Box::into_raw(methods.into_boxed_slice()) as _;
218
+ // }
219
+
220
+ // // __new__ method
221
+ // type_object.tp_new = new;
222
+ // // __call__ method
223
+ // type_object.tp_call = call;
224
+
225
+ // // properties
226
+ // let mut props = py_class_properties::<T>();
227
+
228
+ // if !T::Dict::IS_DUMMY {
229
+ // props.push(ffi::PyGetSetDef_DICT);
230
+ // }
231
+ // if !props.is_empty() {
232
+ // props.push(ffi::PyGetSetDef_INIT);
233
+ // type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as _;
234
+ // }
235
+
236
+ // // set type flags
237
+ // py_class_flags::<T>(type_object);
224
238
}
225
239
226
240
fn py_class_flags < T : PyTypeInfo > ( type_object : & mut ffi:: PyTypeObject ) {
0 commit comments