@@ -194,17 +194,96 @@ pub(crate) mod _ctypes {
194194
195195 #[ pyfunction( name = "sizeof" ) ]
196196 pub fn size_of ( tp : Either < PyTypeRef , PyObjectRef > , vm : & VirtualMachine ) -> PyResult < usize > {
197+ use super :: array:: { PyCArray , PyCArrayType } ;
198+ use super :: structure:: PyCStructure ;
199+ use num_traits:: ToPrimitive ;
200+
197201 match tp {
198202 Either :: A ( type_) if type_. fast_issubclass ( PyCSimple :: static_type ( ) ) => {
199203 let zelf = new_simple_type ( Either :: B ( & type_) , vm) ?;
200204 Ok ( get_size ( zelf. _type_ . as_str ( ) ) )
201205 }
202- Either :: B ( obj) if obj. has_attr ( "size_of_instances" , vm) ? => {
203- let size_of_method = obj. get_attr ( "size_of_instances" , vm) ?;
204- let size_of_return = size_of_method. call ( vec ! [ ] , vm) ?;
205- Ok ( usize:: try_from_object ( vm, size_of_return) ?)
206+ Either :: A ( type_) => {
207+ // Check if it's PyCArrayType (metatype)
208+ if let Some ( array_type) = type_. as_object ( ) . downcast_ref :: < PyCArrayType > ( ) {
209+ let element_type = array_type. inner . typ . read ( ) . clone ( ) ;
210+ let length = array_type. inner . length . load ( ) ;
211+ let element_size = size_of ( Either :: A ( element_type) , vm) . unwrap_or ( 0 ) ;
212+ return Ok ( element_size * length) ;
213+ }
214+ // Check if it's a Structure, Union, or Array type
215+ // Try to get _fields_ for Structure/Union
216+ if let Ok ( fields_attr) = type_. as_object ( ) . get_attr ( "_fields_" , vm) {
217+ // Calculate size from fields
218+ let mut total_size = 0usize ;
219+ if let Ok ( fields) = fields_attr. try_to_value :: < Vec < PyObjectRef > > ( vm) {
220+ for field in fields. iter ( ) {
221+ let Some ( tuple) = field. downcast_ref :: < crate :: builtins:: PyTuple > ( )
222+ else {
223+ continue ;
224+ } ;
225+ let Some ( field_type) = tuple. get ( 1 ) . filter ( |_| tuple. len ( ) >= 2 ) else {
226+ continue ;
227+ } ;
228+ // field_type is a type object, so use Either::A if possible
229+ let field_size = if let Ok ( ft) =
230+ field_type. clone ( ) . downcast :: < crate :: builtins:: PyType > ( )
231+ {
232+ size_of ( Either :: A ( ft) , vm) . unwrap_or ( 0 )
233+ } else {
234+ size_of ( Either :: B ( field_type. clone ( ) ) , vm) . unwrap_or ( 0 )
235+ } ;
236+ total_size += field_size;
237+ }
238+ }
239+ if total_size > 0 {
240+ return Ok ( total_size) ;
241+ }
242+ }
243+ // Try to get _type_ and _length_ for Array type
244+ if let ( Ok ( type_attr) , Ok ( length_attr) ) = (
245+ type_. as_object ( ) . get_attr ( "_type_" , vm) ,
246+ type_. as_object ( ) . get_attr ( "_length_" , vm) ,
247+ ) {
248+ let element_size =
249+ if let Ok ( ta) = type_attr. clone ( ) . downcast :: < crate :: builtins:: PyType > ( ) {
250+ size_of ( Either :: A ( ta) , vm) . unwrap_or ( 0 )
251+ } else {
252+ size_of ( Either :: B ( type_attr) , vm) . unwrap_or ( 0 )
253+ } ;
254+ let length = length_attr. try_int ( vm) ?. as_bigint ( ) . to_usize ( ) . unwrap_or ( 0 ) ;
255+ return Ok ( element_size * length) ;
256+ }
257+ Err ( vm. new_type_error ( "this type has no size" ) )
258+ }
259+ Either :: B ( obj) => {
260+ // Handle PyCArrayType (result of c_int * 5)
261+ if let Some ( array_type) = obj. downcast_ref :: < PyCArrayType > ( ) {
262+ let element_type = array_type. inner . typ . read ( ) . clone ( ) ;
263+ let length = array_type. inner . length . load ( ) ;
264+ let element_size = size_of ( Either :: A ( element_type) , vm) . unwrap_or ( 0 ) ;
265+ return Ok ( element_size * length) ;
266+ }
267+ // Handle instances
268+ if let Some ( structure) = obj. downcast_ref :: < PyCStructure > ( ) {
269+ return Ok ( structure. size . load ( ) ) ;
270+ }
271+ if let Some ( array) = obj. downcast_ref :: < PyCArray > ( ) {
272+ return Ok ( array. length . load ( ) * array. element_size . load ( ) ) ;
273+ }
274+ if let Some ( simple) = obj. downcast_ref :: < PyCSimple > ( ) {
275+ return Ok ( get_size ( & simple. _type_ ) ) ;
276+ }
277+ // Try size_of_instances method
278+ if obj. has_attr ( "size_of_instances" , vm) ? {
279+ let size_of_method = obj. get_attr ( "size_of_instances" , vm) ?;
280+ let size_of_return = size_of_method. call ( vec ! [ ] , vm) ?;
281+ return Ok ( usize:: try_from_object ( vm, size_of_return) ?) ;
282+ }
283+ // Try to get the class and calculate from there
284+ let class = obj. class ( ) ;
285+ size_of ( Either :: A ( class. to_owned ( ) ) , vm)
206286 }
207- _ => Err ( vm. new_type_error ( "this type has no size" ) ) ,
208287 }
209288 }
210289
@@ -365,9 +444,81 @@ pub(crate) mod _ctypes {
365444 }
366445
367446 #[ pyfunction]
368- fn alignment ( _args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( ) > {
369- // TODO: RUSTPYTHON
370- Err ( vm. new_value_error ( "not implemented" ) )
447+ fn alignment ( tp : Either < PyTypeRef , PyObjectRef > , vm : & VirtualMachine ) -> PyResult < usize > {
448+ use super :: array:: { PyCArray , PyCArrayType } ;
449+ use super :: structure:: PyCStructure ;
450+
451+ // Get alignment based on the type
452+ // For simple types, alignment equals size
453+ // For composite types, alignment is the max alignment of members
454+ match tp {
455+ Either :: A ( type_) if type_. fast_issubclass ( PyCSimple :: static_type ( ) ) => {
456+ let zelf = new_simple_type ( Either :: B ( & type_) , vm) ?;
457+ Ok ( get_size ( zelf. _type_ . as_str ( ) ) )
458+ }
459+ Either :: A ( type_) => {
460+ // Check if it's PyCArrayType (metatype)
461+ if let Some ( array_type) = type_. as_object ( ) . downcast_ref :: < PyCArrayType > ( ) {
462+ let element_type = array_type. inner . typ . read ( ) . clone ( ) ;
463+ return alignment ( Either :: A ( element_type) , vm) ;
464+ }
465+ // Check for _fields_ (Structure/Union)
466+ if let Ok ( fields_attr) = type_. as_object ( ) . get_attr ( "_fields_" , vm) {
467+ let mut max_align = 1usize ;
468+ if let Ok ( fields) = fields_attr. try_to_value :: < Vec < PyObjectRef > > ( vm) {
469+ for field in fields. iter ( ) {
470+ let Some ( tuple) = field. downcast_ref :: < crate :: builtins:: PyTuple > ( )
471+ else {
472+ continue ;
473+ } ;
474+ let Some ( field_type) = tuple. get ( 1 ) . filter ( |_| tuple. len ( ) >= 2 ) else {
475+ continue ;
476+ } ;
477+ let field_align = if let Ok ( ft) =
478+ field_type. clone ( ) . downcast :: < crate :: builtins:: PyType > ( )
479+ {
480+ alignment ( Either :: A ( ft) , vm) . unwrap_or ( 1 )
481+ } else {
482+ alignment ( Either :: B ( field_type. clone ( ) ) , vm) . unwrap_or ( 1 )
483+ } ;
484+ max_align = max_align. max ( field_align) ;
485+ }
486+ }
487+ return Ok ( max_align) ;
488+ }
489+ // Check for _type_ (Array)
490+ if let Ok ( type_attr) = type_. as_object ( ) . get_attr ( "_type_" , vm) {
491+ return if let Ok ( ta) = type_attr. clone ( ) . downcast :: < crate :: builtins:: PyType > ( ) {
492+ alignment ( Either :: A ( ta) , vm)
493+ } else {
494+ alignment ( Either :: B ( type_attr) , vm)
495+ } ;
496+ }
497+ // Default alignment
498+ Ok ( 1 )
499+ }
500+ Either :: B ( obj) => {
501+ // Handle PyCArrayType (result of c_int * 5)
502+ if let Some ( array_type) = obj. downcast_ref :: < PyCArrayType > ( ) {
503+ let element_type = array_type. inner . typ . read ( ) . clone ( ) ;
504+ return alignment ( Either :: A ( element_type) , vm) ;
505+ }
506+ // Handle instances
507+ if let Some ( _structure) = obj. downcast_ref :: < PyCStructure > ( ) {
508+ // Get alignment from class
509+ return alignment ( Either :: A ( obj. class ( ) . to_owned ( ) ) , vm) ;
510+ }
511+ if let Some ( array) = obj. downcast_ref :: < PyCArray > ( ) {
512+ return Ok ( array. element_size . load ( ) . min ( 8 ) ) ; // Max alignment is typically 8
513+ }
514+ if let Some ( simple) = obj. downcast_ref :: < PyCSimple > ( ) {
515+ return Ok ( get_size ( & simple. _type_ ) ) ;
516+ }
517+ // Try to get the class and calculate from there
518+ let class = obj. class ( ) ;
519+ alignment ( Either :: A ( class. to_owned ( ) ) , vm)
520+ }
521+ }
371522 }
372523
373524 #[ pyfunction]
0 commit comments