@@ -9,12 +9,13 @@ pub(crate) mod pointer;
99pub ( crate ) mod structure;
1010pub ( crate ) mod thunk;
1111pub ( crate ) mod union;
12+ pub ( crate ) mod util;
1213
1314use crate :: builtins:: PyModule ;
1415use crate :: class:: PyClassImpl ;
1516use crate :: { Py , PyRef , VirtualMachine } ;
1617
17- pub use crate :: stdlib:: ctypes:: base:: { CDataObject , PyCData , PyCSimple , PyCSimpleType } ;
18+ pub use crate :: stdlib:: ctypes:: base:: { PyCData , PyCSimple , PyCSimpleType } ;
1819
1920pub fn extend_module_nodes ( vm : & VirtualMachine , module : & Py < PyModule > ) {
2021 let ctx = & vm. ctx ;
@@ -52,7 +53,7 @@ pub(crate) mod _ctypes {
5253 use crate :: convert:: ToPyObject ;
5354 use crate :: function:: { Either , FuncArgs , OptionalArg } ;
5455 use crate :: stdlib:: ctypes:: library;
55- use crate :: { AsObject , PyObjectRef , PyPayload , PyResult , TryFromObject , VirtualMachine } ;
56+ use crate :: { AsObject , PyObjectRef , PyPayload , PyResult , VirtualMachine } ;
5657 use crossbeam_utils:: atomic:: AtomicCell ;
5758 use std:: ffi:: {
5859 c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong,
@@ -159,6 +160,11 @@ pub(crate) mod _ctypes {
159160 }
160161 }
161162
163+ /// Get alignment for a simple type - for C types, alignment equals size
164+ pub fn get_align ( ty : & str ) -> usize {
165+ get_size ( ty)
166+ }
167+
162168 /// Get the size of a ctypes type from its type object
163169 #[ allow( dead_code) ]
164170 pub fn get_size_from_type ( cls : & PyTypeRef , vm : & VirtualMachine ) -> PyResult < usize > {
@@ -366,7 +372,7 @@ pub(crate) mod _ctypes {
366372 Ok ( PyCSimple {
367373 _type_ : tp_str,
368374 value : AtomicCell :: new ( vm. ctx . none ( ) ) ,
369- cdata : rustpython_common:: lock:: PyRwLock :: new ( CDataObject :: new ( size) ) ,
375+ cdata : rustpython_common:: lock:: PyRwLock :: new ( CDataObject :: from_bytes ( vec ! [ 0u8 ; size] , None ) ) ,
370376 } )
371377 }
372378 } else {
@@ -378,95 +384,52 @@ pub(crate) mod _ctypes {
378384 }
379385
380386 /// Get the size of a ctypes type or instance
381- ///
382- /// This function accepts:
383- /// - A ctypes type (e.g., c_int, Structure subclass)
384- /// - A ctypes instance (e.g., c_int(5))
385387 #[ pyfunction( name = "sizeof" ) ]
386388 pub fn size_of ( obj : PyObjectRef , vm : & VirtualMachine ) -> PyResult < usize > {
387- use super :: array:: PyCArray ;
389+ use super :: array:: { PyCArray , PyCArrayType } ;
388390 use super :: pointer:: PyCPointer ;
389391 use super :: structure:: PyCStructure ;
390- use super :: union:: PyCUnion ;
391-
392- // Check if obj is a type
393- if let Ok ( type_ref) = obj. clone ( ) . downcast :: < crate :: builtins:: PyType > ( ) {
394- // It's a type - check what kind of ctypes type it is
395-
396- // Simple types (c_int, c_char, etc.)
397- if type_ref. fast_issubclass ( PyCSimple :: static_type ( ) ) {
398- let zelf = new_simple_type ( Either :: B ( & type_ref) , vm) ?;
399- return Ok ( get_size ( zelf. _type_ . as_str ( ) ) ) ;
400- }
401-
402- // Array types
403- if type_ref. fast_issubclass ( PyCArray :: static_type ( ) ) {
404- // Get _length_ and element size
405- if let Ok ( length) = type_ref. as_object ( ) . get_attr ( "_length_" , vm) {
406- let length = usize:: try_from_object ( vm, length) ?;
407- if let Ok ( elem_type) = type_ref. as_object ( ) . get_attr ( "_type_" , vm) {
408- let elem_size = size_of ( elem_type, vm) ?;
409- return Ok ( length * elem_size) ;
410- }
411- }
412- }
413-
414- // Structure types - check for size_of_instances method
415- if type_ref. fast_issubclass ( PyCStructure :: static_type ( ) )
416- || type_ref. fast_issubclass ( PyCUnion :: static_type ( ) )
417- {
418- if let Ok ( size_method) = type_ref. as_object ( ) . get_attr ( "size_of_instances" , vm) {
419- let size = size_method. call ( vec ! [ ] , vm) ?;
420- return Ok ( usize:: try_from_object ( vm, size) ?) ;
421- }
422- }
423-
424- // Pointer types
425- if type_ref. fast_issubclass ( PyCPointer :: static_type ( ) ) {
426- return Ok ( std:: mem:: size_of :: < usize > ( ) ) ;
427- }
392+ use super :: union:: { PyCUnion , PyCUnionType } ;
428393
429- // Check for size_of_instances as a fallback
430- if let Ok ( size_method) = type_ref. as_object ( ) . get_attr ( "size_of_instances" , vm) {
431- let size = size_method. call ( vec ! [ ] , vm) ?;
432- return Ok ( usize:: try_from_object ( vm, size) ?) ;
394+ // 1. Instances with stg_info
395+ if obj. fast_isinstance ( PyCArray :: static_type ( ) ) {
396+ // Get stg_info from the type
397+ if let Some ( type_obj) = obj. class ( ) . as_object ( ) . downcast_ref :: < PyCArrayType > ( ) {
398+ return Ok ( type_obj. stg_info . size ) ;
433399 }
434-
435- return Err ( vm. new_type_error ( "this type has no size" ) ) ;
436- }
437-
438- // It's an instance - get size from instance or its class
439-
440- // Simple type instance
441- if let Ok ( simple) = obj. clone ( ) . downcast :: < PyCSimple > ( ) {
442- return Ok ( get_size ( simple. _type_ . as_str ( ) ) ) ;
443- }
444-
445- // Array instance
446- if let Ok ( array) = obj. clone ( ) . downcast :: < PyCArray > ( ) {
447- return Ok ( array. cdata . read ( ) . size ( ) ) ;
448400 }
449-
450- // Structure instance
451- if let Ok ( structure) = obj. clone ( ) . downcast :: < PyCStructure > ( ) {
401+ if let Some ( structure) = obj. downcast_ref :: < PyCStructure > ( ) {
452402 return Ok ( structure. cdata . read ( ) . size ( ) ) ;
453403 }
454-
455- // Union instance
456- if let Ok ( union) = obj. clone ( ) . downcast :: < PyCUnion > ( ) {
457- return Ok ( union. cdata . read ( ) . size ( ) ) ;
404+ if obj. fast_isinstance ( PyCUnion :: static_type ( ) ) {
405+ // Get stg_info from the type
406+ if let Some ( type_obj) = obj. class ( ) . as_object ( ) . downcast_ref :: < PyCUnionType > ( ) {
407+ return Ok ( type_obj. stg_info . size ) ;
408+ }
409+ }
410+ if let Some ( simple) = obj. downcast_ref :: < PyCSimple > ( ) {
411+ return Ok ( simple. cdata . read ( ) . size ( ) ) ;
458412 }
459-
460- // Pointer instance
461413 if obj. fast_isinstance ( PyCPointer :: static_type ( ) ) {
462414 return Ok ( std:: mem:: size_of :: < usize > ( ) ) ;
463415 }
464416
465- // Check if the object has size_of_instances method (for custom types)
466- if obj. has_attr ( "size_of_instances" , vm) ? {
467- let size_method = obj. get_attr ( "size_of_instances" , vm) ?;
468- let size = size_method. call ( vec ! [ ] , vm) ?;
469- return Ok ( usize:: try_from_object ( vm, size) ?) ;
417+ // 2. Types (metatypes with stg_info)
418+ if let Some ( array_type) = obj. downcast_ref :: < PyCArrayType > ( ) {
419+ return Ok ( array_type. stg_info . size ) ;
420+ }
421+
422+ // 3. Type objects
423+ if let Ok ( type_ref) = obj. clone ( ) . downcast :: < crate :: builtins:: PyType > ( ) {
424+ // Simple types (c_int, c_char, etc.)
425+ if type_ref. fast_issubclass ( PyCSimple :: static_type ( ) ) {
426+ let instance = new_simple_type ( Either :: B ( & type_ref) , vm) ?;
427+ return Ok ( get_size ( & instance. _type_ ) ) ;
428+ }
429+ // Pointer types
430+ if type_ref. fast_issubclass ( PyCPointer :: static_type ( ) ) {
431+ return Ok ( std:: mem:: size_of :: < usize > ( ) ) ;
432+ }
470433 }
471434
472435 Err ( vm. new_type_error ( "this type has no size" ) )
@@ -630,9 +593,100 @@ pub(crate) mod _ctypes {
630593 }
631594
632595 #[ pyfunction]
633- fn alignment ( _args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( ) > {
634- // TODO: RUSTPYTHON
635- Err ( vm. new_value_error ( "not implemented" ) )
596+ fn alignment ( tp : Either < PyTypeRef , PyObjectRef > , vm : & VirtualMachine ) -> PyResult < usize > {
597+ use super :: array:: { PyCArray , PyCArrayType } ;
598+ use super :: base:: PyCSimpleType ;
599+ use super :: pointer:: PyCPointer ;
600+ use super :: structure:: PyCStructure ;
601+ use super :: union:: PyCUnion ;
602+
603+ let obj = match & tp {
604+ Either :: A ( t) => t. as_object ( ) ,
605+ Either :: B ( o) => o. as_ref ( ) ,
606+ } ;
607+
608+ // Try to get alignment from stg_info directly (for instances)
609+ if let Some ( array_type) = obj. downcast_ref :: < PyCArrayType > ( ) {
610+ return Ok ( array_type. stg_info . align ) ;
611+ }
612+ if obj. fast_isinstance ( PyCSimple :: static_type ( ) ) {
613+ // Get stg_info from the type by reading _type_ attribute
614+ let cls = obj. class ( ) . to_owned ( ) ;
615+ let stg_info = PyCSimpleType :: get_stg_info ( & cls, vm) ;
616+ return Ok ( stg_info. align ) ;
617+ }
618+ if obj. fast_isinstance ( PyCArray :: static_type ( ) ) {
619+ // Get stg_info from the type
620+ if let Some ( type_obj) = obj. class ( ) . as_object ( ) . downcast_ref :: < PyCArrayType > ( ) {
621+ return Ok ( type_obj. stg_info . align ) ;
622+ }
623+ }
624+ if obj. fast_isinstance ( PyCStructure :: static_type ( ) ) {
625+ // Calculate alignment from _fields_
626+ let cls = obj. class ( ) ;
627+ return alignment ( Either :: A ( cls. to_owned ( ) ) , vm) ;
628+ }
629+ if obj. fast_isinstance ( PyCPointer :: static_type ( ) ) {
630+ // Pointer alignment is always pointer size
631+ return Ok ( std:: mem:: align_of :: < usize > ( ) ) ;
632+ }
633+ if obj. fast_isinstance ( PyCUnion :: static_type ( ) ) {
634+ // Calculate alignment from _fields_
635+ let cls = obj. class ( ) ;
636+ return alignment ( Either :: A ( cls. to_owned ( ) ) , vm) ;
637+ }
638+
639+ // Get the type object to check
640+ let type_obj: PyObjectRef = match & tp {
641+ Either :: A ( t) => t. clone ( ) . into ( ) ,
642+ Either :: B ( obj) => obj. class ( ) . to_owned ( ) . into ( ) ,
643+ } ;
644+
645+ // For type objects, try to get alignment from _type_ attribute
646+ if let Ok ( type_attr) = type_obj. get_attr ( "_type_" , vm) {
647+ // Array/Pointer: _type_ is the element type (a PyType)
648+ if let Ok ( elem_type) = type_attr. clone ( ) . downcast :: < crate :: builtins:: PyType > ( ) {
649+ return alignment ( Either :: A ( elem_type) , vm) ;
650+ }
651+ // Simple type: _type_ is a single character string
652+ if let Ok ( s) = type_attr. str ( vm) {
653+ let ty = s. to_string ( ) ;
654+ if ty. len ( ) == 1 && SIMPLE_TYPE_CHARS . contains ( ty. as_str ( ) ) {
655+ return Ok ( get_align ( & ty) ) ;
656+ }
657+ }
658+ }
659+
660+ // Structure/Union: max alignment of fields
661+ if let Ok ( fields_attr) = type_obj. get_attr ( "_fields_" , vm)
662+ && let Ok ( fields) = fields_attr. try_to_value :: < Vec < PyObjectRef > > ( vm)
663+ {
664+ let mut max_align = 1usize ;
665+ for field in fields. iter ( ) {
666+ if let Some ( tuple) = field. downcast_ref :: < crate :: builtins:: PyTuple > ( )
667+ && let Some ( field_type) = tuple. get ( 1 )
668+ {
669+ let align =
670+ if let Ok ( ft) = field_type. clone ( ) . downcast :: < crate :: builtins:: PyType > ( ) {
671+ alignment ( Either :: A ( ft) , vm) . unwrap_or ( 1 )
672+ } else {
673+ 1
674+ } ;
675+ max_align = max_align. max ( align) ;
676+ }
677+ }
678+ return Ok ( max_align) ;
679+ }
680+
681+ // For instances, delegate to their class
682+ if let Either :: B ( obj) = & tp
683+ && !obj. class ( ) . is ( vm. ctx . types . type_type . as_ref ( ) )
684+ {
685+ return alignment ( Either :: A ( obj. class ( ) . to_owned ( ) ) , vm) ;
686+ }
687+
688+ // No alignment info found
689+ Err ( vm. new_type_error ( "no alignment info" ) )
636690 }
637691
638692 #[ pyfunction]
0 commit comments