11use crate :: atomic_func;
22use crate :: builtins:: { PyBytes , PyInt } ;
3- use crate :: convert :: ToPyObject ;
3+ use crate :: class :: StaticType ;
44use crate :: function:: FuncArgs ;
55use crate :: protocol:: {
66 BufferDescriptor , BufferMethods , PyBuffer , PyNumberMethods , PySequenceMethods ,
77} ;
88use crate :: stdlib:: ctypes:: base:: CDataObject ;
99use crate :: stdlib:: ctypes:: util:: StgInfo ;
10- use crate :: types:: { AsBuffer , AsNumber , AsSequence , Callable } ;
10+ use crate :: types:: { AsBuffer , AsNumber , AsSequence } ;
1111use crate :: { AsObject , Py , PyObjectRef , PyPayload } ;
1212use crate :: {
1313 PyResult , VirtualMachine ,
@@ -20,56 +20,49 @@ use rustpython_common::lock::PyRwLock;
2020use rustpython_vm:: stdlib:: ctypes:: _ctypes:: get_size;
2121use rustpython_vm:: stdlib:: ctypes:: base:: PyCData ;
2222
23+ /// PyCArrayType - metatype for Array types
24+ /// CPython stores array info (type, length) in StgInfo via type_data
2325#[ pyclass( name = "PyCArrayType" , base = PyType , module = "_ctypes" ) ]
24- #[ derive( PyPayload ) ]
25- pub struct PyCArrayType {
26- pub ( super ) stg_info : StgInfo ,
27- pub ( super ) typ : PyRwLock < PyObjectRef > ,
28- pub ( super ) length : AtomicCell < usize > ,
29- pub ( super ) element_size : AtomicCell < usize > ,
30- }
31-
32- impl std:: fmt:: Debug for PyCArrayType {
33- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
34- f. debug_struct ( "PyCArrayType" )
35- . field ( "typ" , & self . typ )
36- . field ( "length" , & self . length )
37- . finish ( )
38- }
39- }
40-
41- impl Callable for PyCArrayType {
42- type Args = FuncArgs ;
43- fn call ( zelf : & Py < Self > , args : Self :: Args , vm : & VirtualMachine ) -> PyResult {
44- // Create an instance of the array
45- let element_type = zelf. typ . read ( ) . clone ( ) ;
46- let length = zelf. length . load ( ) ;
47- let element_size = zelf. element_size . load ( ) ;
48- let total_size = element_size * length;
49- let mut buffer = vec ! [ 0u8 ; total_size] ;
50-
51- // Initialize from positional arguments
52- for ( i, value) in args. args . iter ( ) . enumerate ( ) {
53- if i >= length {
54- break ;
55- }
56- let offset = i * element_size;
57- if let Ok ( int_val) = value. try_int ( vm) {
58- let bytes = PyCArray :: int_to_bytes ( int_val. as_bigint ( ) , element_size) ;
59- if offset + element_size <= buffer. len ( ) {
60- buffer[ offset..offset + element_size] . copy_from_slice ( & bytes) ;
61- }
62- }
26+ #[ derive( Debug , Default , PyPayload ) ]
27+ pub struct PyCArrayType { }
28+
29+ /// Create a new Array type with StgInfo stored in type_data (CPython style)
30+ pub fn create_array_type_with_stginfo ( stg_info : StgInfo , vm : & VirtualMachine ) -> PyResult {
31+ // Get PyCArrayType as metaclass
32+ let metaclass = PyCArrayType :: static_type ( ) . to_owned ( ) ;
33+
34+ // Create a unique name for the array type
35+ let type_name = format ! ( "Array_{}" , stg_info. length) ;
36+
37+ // Create args for type(): (name, bases, dict)
38+ let name = vm. ctx . new_str ( type_name) ;
39+ let bases = vm
40+ . ctx
41+ . new_tuple ( vec ! [ PyCArray :: static_type( ) . to_owned( ) . into( ) ] ) ;
42+ let dict = vm. ctx . new_dict ( ) ;
43+
44+ let args = FuncArgs :: new (
45+ vec ! [ name. into( ) , bases. into( ) , dict. into( ) ] ,
46+ crate :: function:: KwArgs :: default ( ) ,
47+ ) ;
48+
49+ // Create the new type using PyType::slot_new with PyCArrayType as metaclass
50+ let new_type = crate :: builtins:: type_:: PyType :: slot_new ( metaclass, args, vm) ?;
51+
52+ // Set StgInfo in type_data
53+ let type_ref: PyTypeRef = new_type
54+ . clone ( )
55+ . downcast ( )
56+ . map_err ( |_| vm. new_type_error ( "Failed to create array type" . to_owned ( ) ) ) ?;
57+
58+ if type_ref. init_type_data ( stg_info. clone ( ) ) . is_err ( ) {
59+ // Type data already initialized - update it
60+ if let Some ( mut existing) = type_ref. get_type_data_mut :: < StgInfo > ( ) {
61+ * existing = stg_info;
6362 }
64-
65- Ok ( PyCArray {
66- typ : PyRwLock :: new ( element_type) ,
67- length : AtomicCell :: new ( length) ,
68- element_size : AtomicCell :: new ( element_size) ,
69- cdata : PyRwLock :: new ( CDataObject :: from_bytes ( buffer, None ) ) ,
70- }
71- . into_pyobject ( vm) )
7263 }
64+
65+ Ok ( new_type)
7366}
7467
7568impl Constructor for PyCArrayType {
@@ -80,54 +73,62 @@ impl Constructor for PyCArrayType {
8073 }
8174}
8275
83- #[ pyclass( flags( IMMUTABLETYPE ) , with( Callable , Constructor , AsNumber ) ) ]
76+ #[ pyclass( flags( IMMUTABLETYPE ) , with( Constructor , AsNumber ) ) ]
8477impl PyCArrayType {
8578 #[ pygetset( name = "_type_" ) ]
86- fn typ ( & self ) -> PyObjectRef {
87- self . typ . read ( ) . clone ( )
79+ fn typ ( zelf : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
80+ zelf. downcast_ref :: < PyType > ( )
81+ . and_then ( |t| t. get_type_data :: < StgInfo > ( ) )
82+ . and_then ( |stg| stg. element_type . clone ( ) )
83+ . unwrap_or_else ( || vm. ctx . none ( ) )
8884 }
8985
9086 #[ pygetset( name = "_length_" ) ]
91- fn length ( & self ) -> usize {
92- self . length . load ( )
87+ fn length ( zelf : PyObjectRef ) -> usize {
88+ zelf. downcast_ref :: < PyType > ( )
89+ . and_then ( |t| t. get_type_data :: < StgInfo > ( ) )
90+ . map ( |stg| stg. length )
91+ . unwrap_or ( 0 )
9392 }
9493
9594 #[ pymethod]
96- fn __mul__ ( zelf : & Py < Self > , n : isize , vm : & VirtualMachine ) -> PyResult {
95+ fn __mul__ ( zelf : PyObjectRef , n : isize , vm : & VirtualMachine ) -> PyResult {
9796 if n < 0 {
9897 return Err ( vm. new_value_error ( format ! ( "Array length must be >= 0, not {n}" ) ) ) ;
9998 }
100- // Create a nested array type: (inner_type * inner_length) * n
101- // The new array has n elements, each element is the current array type
102- // e.g., (c_int * 5) * 3 = Array of 3 elements, each is (c_int * 5)
103- let inner_length = zelf. length . load ( ) ;
104- let inner_element_size = zelf. element_size . load ( ) ;
99+
100+ // Get inner array info from TypeDataSlot
101+ let type_ref = zelf. downcast_ref :: < PyType > ( ) . unwrap ( ) ;
102+ let ( _inner_length, inner_size) = type_ref
103+ . get_type_data :: < StgInfo > ( )
104+ . map ( |stg| ( stg. length , stg. size ) )
105+ . unwrap_or ( ( 0 , 0 ) ) ;
105106
106107 // The element type of the new array is the current array type itself
107- let current_array_type: PyObjectRef = zelf. as_object ( ) . to_owned ( ) ;
108+ let current_array_type: PyObjectRef = zelf. clone ( ) ;
108109
109110 // Element size is the total size of the inner array
110- let new_element_size = inner_length * inner_element_size ;
111+ let new_element_size = inner_size ;
111112 let total_size = new_element_size * ( n as usize ) ;
112- let stg_info = StgInfo :: new ( total_size, inner_element_size) ;
113113
114- Ok ( PyCArrayType {
115- stg_info,
116- typ : PyRwLock :: new ( current_array_type) ,
117- length : AtomicCell :: new ( n as usize ) ,
118- element_size : AtomicCell :: new ( new_element_size) ,
119- }
120- . to_pyobject ( vm) )
114+ let stg_info = StgInfo :: new_array (
115+ total_size,
116+ new_element_size,
117+ n as usize ,
118+ current_array_type,
119+ new_element_size,
120+ ) ;
121+
122+ create_array_type_with_stginfo ( stg_info, vm)
121123 }
122124
123125 #[ pyclassmethod]
124126 fn in_dll (
125- zelf : & Py < Self > ,
127+ zelf : PyObjectRef ,
126128 dll : PyObjectRef ,
127129 name : crate :: builtins:: PyStrRef ,
128130 vm : & VirtualMachine ,
129131 ) -> PyResult {
130- use crate :: stdlib:: ctypes:: _ctypes:: size_of;
131132 use libloading:: Symbol ;
132133
133134 // Get the library handle from dll object
@@ -168,10 +169,18 @@ impl PyCArrayType {
168169 return Err ( vm. new_attribute_error ( "Library is closed" . to_owned ( ) ) ) ;
169170 } ;
170171
171- // Get size from the array type
172- let element_type = zelf. typ . read ( ) . clone ( ) ;
173- let length = zelf. length . load ( ) ;
174- let element_size = size_of ( element_type. clone ( ) , vm) ?;
172+ // Get size from the array type via TypeDataSlot
173+ let type_ref = zelf. downcast_ref :: < PyType > ( ) . unwrap ( ) ;
174+ let ( element_type, length, element_size) = type_ref
175+ . get_type_data :: < StgInfo > ( )
176+ . map ( |stg| {
177+ (
178+ stg. element_type . clone ( ) . unwrap_or_else ( || vm. ctx . none ( ) ) ,
179+ stg. length ,
180+ stg. element_size ,
181+ )
182+ } )
183+ . unwrap_or_else ( || ( vm. ctx . none ( ) , 0 , 0 ) ) ;
175184 let total_size = element_size * length;
176185
177186 // Read data from symbol address
@@ -206,15 +215,13 @@ impl AsNumber for PyCArrayType {
206215 fn as_number ( ) -> & ' static PyNumberMethods {
207216 static AS_NUMBER : PyNumberMethods = PyNumberMethods {
208217 multiply : Some ( |a, b, vm| {
209- let zelf = a
210- . downcast_ref :: < PyCArrayType > ( )
211- . ok_or_else ( || vm. new_type_error ( "expected PyCArrayType" . to_owned ( ) ) ) ?;
218+ // a is a type object whose metaclass is PyCArrayType (e.g., Array_5)
212219 let n = b
213220 . try_index ( vm) ?
214221 . as_bigint ( )
215222 . to_isize ( )
216223 . ok_or_else ( || vm. new_overflow_error ( "array size too large" . to_owned ( ) ) ) ?;
217- PyCArrayType :: __mul__ ( zelf , n, vm)
224+ PyCArrayType :: __mul__ ( a . to_owned ( ) , n, vm)
218225 } ) ,
219226 ..PyNumberMethods :: NOT_IMPLEMENTED
220227 } ;
0 commit comments