🌐 AI搜索 & 代理 主页
Skip to content

Commit 9f82068

Browse files
committed
ctypes
1 parent d46e046 commit 9f82068

File tree

7 files changed

+199
-88
lines changed

7 files changed

+199
-88
lines changed

crates/vm/src/stdlib/ctypes/array.rs

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use crate::atomic_func;
22
use crate::builtins::{PyBytes, PyInt};
3-
use crate::convert::ToPyObject;
4-
use crate::function::FuncArgs;
3+
use crate::class::StaticType;
4+
use crate::function::{FuncArgs, KwArgs};
55
use crate::protocol::{
66
BufferDescriptor, BufferMethods, PyBuffer, PyNumberMethods, PySequenceMethods,
77
};
88
use crate::stdlib::ctypes::base::CDataObject;
99
use crate::stdlib::ctypes::util::StgInfo;
1010
use crate::types::{AsBuffer, AsNumber, AsSequence, Callable};
11-
use crate::{AsObject, Py, PyObjectRef, PyPayload};
11+
use crate::{AsObject, Py, PyObjectRef, PyPayload, PyRef};
1212
use crate::{
1313
PyResult, VirtualMachine,
1414
builtins::{PyType, PyTypeRef},
@@ -22,6 +22,7 @@ use rustpython_vm::stdlib::ctypes::base::PyCData;
2222

2323
#[pyclass(name = "PyCArrayType", base = PyType, module = "_ctypes")]
2424
pub struct PyCArrayType {
25+
pub base: PyType,
2526
pub(super) stg_info: StgInfo,
2627
pub(super) typ: PyRwLock<PyObjectRef>,
2728
pub(super) length: AtomicCell<usize>,
@@ -71,11 +72,94 @@ impl Callable for PyCArrayType {
7172
}
7273
}
7374

75+
impl PyCArrayType {
76+
/// Create a new array type dynamically (like c_int * 5)
77+
pub fn create_array_type(
78+
element_type: PyObjectRef,
79+
length: usize,
80+
element_size: usize,
81+
metatype: &Py<PyType>,
82+
vm: &VirtualMachine,
83+
) -> PyResult<PyObjectRef> {
84+
use crate::builtins::PyTuple;
85+
use crate::function::{FuncArgs, KwArgs};
86+
87+
let total_size = element_size * length;
88+
let stg_info = StgInfo::new(total_size, element_size);
89+
90+
// Create base PyType using type(name, bases, dict) pattern
91+
let name = vm
92+
.ctx
93+
.new_str(format!("{}_Array_{}", metatype.name(), length));
94+
let bases = PyTuple::new_ref(vec![element_type.clone()], &vm.ctx);
95+
let dict = vm.ctx.new_dict();
96+
dict.set_item("_length_", vm.ctx.new_int(length).into(), vm)?;
97+
dict.set_item("_type_", element_type.clone(), vm)?;
98+
99+
let args = FuncArgs::new(
100+
vec![name.into(), bases.into(), dict.into()],
101+
KwArgs::default(),
102+
);
103+
let base = crate::builtins::type_::PyType::py_new(metatype, args, vm)?;
104+
105+
let payload = PyCArrayType {
106+
base,
107+
stg_info,
108+
typ: PyRwLock::new(element_type),
109+
length: AtomicCell::new(length),
110+
element_size: AtomicCell::new(element_size),
111+
};
112+
let array_metatype = PyCArrayType::static_type();
113+
let typ_ref = payload.into_ref_with_type(vm, array_metatype.to_owned())?;
114+
115+
// Finalize heap type (register subclass, member descriptors, etc.)
116+
let type_ref: PyTypeRef = typ_ref
117+
.as_object()
118+
.to_owned()
119+
.downcast()
120+
.expect("metaclass should downcast to PyType");
121+
PyType::finalize_heap_type(&type_ref, KwArgs::default(), vm)?;
122+
123+
Ok(typ_ref.into())
124+
}
125+
}
126+
74127
impl Constructor for PyCArrayType {
75-
type Args = PyObjectRef;
128+
type Args = FuncArgs;
129+
130+
fn py_new(metatype: &Py<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Self> {
131+
// 1. Create the base type using PyType::py_new
132+
let base = crate::builtins::type_::PyType::py_new(metatype, args, vm)?;
133+
134+
// 2. Return PyCArrayType with the base and default values
135+
// The actual _length_ and _type_ will be set after type creation via __init__
136+
Ok(PyCArrayType {
137+
base,
138+
stg_info: StgInfo::default(),
139+
typ: PyRwLock::new(vm.ctx.none()),
140+
length: AtomicCell::new(0),
141+
element_size: AtomicCell::new(0),
142+
})
143+
}
144+
145+
fn py_new_ref(
146+
metatype: PyTypeRef,
147+
args: FuncArgs,
148+
vm: &VirtualMachine,
149+
) -> PyResult<PyRef<Self>> {
150+
let payload = Self::py_new(&metatype, args, vm)?;
151+
let array_metatype = PyCArrayType::static_type();
152+
let typ_ref = payload.into_ref_with_type(vm, array_metatype.to_owned())?;
153+
154+
// Finalize heap type (register subclass, member descriptors, etc.)
155+
let type_ref: PyTypeRef = typ_ref
156+
.as_object()
157+
.to_owned()
158+
.downcast()
159+
.expect("metaclass should downcast to PyType");
160+
PyType::finalize_heap_type(&type_ref, KwArgs::default(), vm)?;
76161

77-
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
78-
unreachable!()
162+
Ok(typ_ref)
79163
}
80164
}
81165

@@ -107,16 +191,14 @@ impl PyCArrayType {
107191

108192
// Element size is the total size of the inner array
109193
let new_element_size = inner_length * inner_element_size;
110-
let total_size = new_element_size * (n as usize);
111-
let stg_info = StgInfo::new(total_size, inner_element_size);
112194

113-
Ok(PyCArrayType {
114-
stg_info,
115-
typ: PyRwLock::new(current_array_type),
116-
length: AtomicCell::new(n as usize),
117-
element_size: AtomicCell::new(new_element_size),
118-
}
119-
.to_pyobject(vm))
195+
PyCArrayType::create_array_type(
196+
current_array_type,
197+
n as usize,
198+
new_element_size,
199+
zelf.class(),
200+
vm,
201+
)
120202
}
121203

122204
#[pyclassmethod]

crates/vm/src/stdlib/ctypes/base.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use super::_ctypes::bytes_to_pyobject;
22
use super::array::PyCArrayType;
33
use super::util::StgInfo;
44
use crate::builtins::{PyBytes, PyFloat, PyInt, PyNone, PyStr, PyStrRef, PyType, PyTypeRef};
5-
use crate::convert::ToPyObject;
65
use crate::function::{ArgBytesLike, Either, OptionalArg};
76
use crate::protocol::{BufferDescriptor, BufferMethods, PyBuffer, PyNumberMethods};
87
use crate::stdlib::ctypes::_ctypes::new_simple_type;
@@ -230,8 +229,9 @@ impl PyCData {
230229
}
231230

232231
#[pyclass(module = "_ctypes", name = "PyCSimpleType", base = PyType)]
233-
#[derive(Debug, Default)]
232+
#[derive(Debug)]
234233
pub struct PyCSimpleType {
234+
pub base: PyType,
235235
#[allow(dead_code)]
236236
pub stg_info: StgInfo,
237237
}
@@ -757,15 +757,7 @@ impl PyCSimple {
757757
} else {
758758
std::mem::size_of::<usize>()
759759
};
760-
let total_size = element_size * (n as usize);
761-
let stg_info = super::util::StgInfo::new(total_size, element_size);
762-
Ok(PyCArrayType {
763-
stg_info,
764-
typ: PyRwLock::new(cls.clone().into()),
765-
length: AtomicCell::new(n as usize),
766-
element_size: AtomicCell::new(element_size),
767-
}
768-
.to_pyobject(vm))
760+
PyCArrayType::create_array_type(cls.clone().into(), n as usize, element_size, &cls, vm)
769761
}
770762

771763
#[pyclassmethod]

crates/vm/src/stdlib/ctypes/field.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::union::PyCUnion;
1010
#[pyclass(name = "PyCFieldType", base = PyType, module = "_ctypes")]
1111
#[derive(Debug)]
1212
pub struct PyCFieldType {
13+
pub base: PyType,
1314
#[allow(dead_code)]
1415
pub(super) inner: PyCField,
1516
}

crates/vm/src/stdlib/ctypes/pointer.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
use crossbeam_utils::atomic::AtomicCell;
21
use num_traits::ToPrimitive;
32
use rustpython_common::lock::PyRwLock;
43

54
use crate::Py;
65
use crate::builtins::{PyType, PyTypeRef};
7-
use crate::convert::ToPyObject;
86
use crate::protocol::PyNumberMethods;
97
use crate::stdlib::ctypes::PyCData;
8+
use crate::stdlib::ctypes::base::CDataObject;
109
use crate::types::{AsNumber, Constructor};
1110
use crate::{AsObject, PyObjectRef, PyPayload, PyResult, VirtualMachine};
1211

@@ -15,6 +14,8 @@ use super::util::StgInfo;
1514
#[pyclass(name = "PyCPointerType", base = PyType, module = "_ctypes")]
1615
#[derive(Debug)]
1716
pub struct PyCPointerType {
17+
#[allow(dead_code)]
18+
pub base: PyType,
1819
#[allow(dead_code)]
1920
pub stg_info: StgInfo,
2021
}
@@ -29,16 +30,13 @@ impl PyCPointerType {
2930
}
3031
// Pointer size
3132
let element_size = std::mem::size_of::<usize>();
32-
let total_size = element_size * (n as usize);
33-
let mut stg_info = super::util::StgInfo::new(total_size, element_size);
34-
stg_info.length = n as usize;
35-
Ok(PyCArrayType {
36-
stg_info,
37-
typ: PyRwLock::new(cls.as_object().to_owned()),
38-
length: AtomicCell::new(n as usize),
39-
element_size: AtomicCell::new(element_size),
40-
}
41-
.to_pyobject(vm))
33+
PyCArrayType::create_array_type(
34+
cls.as_object().to_owned(),
35+
n as usize,
36+
element_size,
37+
&cls,
38+
vm,
39+
)
4240
}
4341
}
4442

@@ -70,18 +68,30 @@ impl AsNumber for PyCPointerType {
7068
)]
7169
#[derive(Debug)]
7270
pub struct PyCPointer {
71+
#[allow(dead_code)]
72+
base: PyCData,
7373
contents: PyRwLock<PyObjectRef>,
7474
}
7575

76+
impl PyCPointer {
77+
fn make_base() -> PyCData {
78+
let stg_info = StgInfo::new(std::mem::size_of::<usize>(), std::mem::align_of::<usize>());
79+
PyCData {
80+
cdata: PyRwLock::new(CDataObject::from_stg_info(&stg_info)),
81+
}
82+
}
83+
}
84+
7685
impl Constructor for PyCPointer {
7786
type Args = (crate::function::OptionalArg<PyObjectRef>,);
7887

79-
fn py_new(cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
88+
fn py_new(_cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
8089
// Get the initial contents value if provided
8190
let initial_contents = args.0.into_option().unwrap_or_else(|| vm.ctx.none());
8291

8392
// Create a new PyCPointer instance with the provided value
8493
Ok(PyCPointer {
94+
base: Self::make_base(),
8595
contents: PyRwLock::new(initial_contents),
8696
})
8797
}
@@ -125,6 +135,7 @@ impl PyCPointer {
125135
}
126136
// Pointer just stores the address value
127137
let payload = PyCPointer {
138+
base: Self::make_base(),
128139
contents: PyRwLock::new(vm.ctx.new_int(address).into()),
129140
};
130141
payload.into_ref_with_type(vm, cls).map(Into::into)
@@ -168,6 +179,7 @@ impl PyCPointer {
168179
let ptr_val = usize::from_ne_bytes(ptr_bytes.try_into().expect("size is checked above"));
169180

170181
let payload = PyCPointer {
182+
base: Self::make_base(),
171183
contents: PyRwLock::new(vm.ctx.new_int(ptr_val).into()),
172184
};
173185
payload.into_ref_with_type(vm, cls).map(Into::into)
@@ -203,6 +215,7 @@ impl PyCPointer {
203215
let ptr_val = usize::from_ne_bytes(ptr_bytes.try_into().expect("size is checked above"));
204216

205217
let payload = PyCPointer {
218+
base: Self::make_base(),
206219
contents: PyRwLock::new(vm.ctx.new_int(ptr_val).into()),
207220
};
208221
payload.into_ref_with_type(vm, cls).map(Into::into)
@@ -257,6 +270,7 @@ impl PyCPointer {
257270

258271
// For pointer types, we return a pointer to the symbol address
259272
let payload = PyCPointer {
273+
base: Self::make_base(),
260274
contents: PyRwLock::new(vm.ctx.new_int(symbol_address).into()),
261275
};
262276
payload.into_ref_with_type(vm, cls).map(Into::into)

crates/vm/src/stdlib/ctypes/structure.rs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ use super::base::{CDataObject, PyCData};
22
use super::field::PyCField;
33
use super::util::StgInfo;
44
use crate::builtins::{PyList, PyStr, PyTuple, PyType, PyTypeRef};
5+
use crate::class::StaticType;
56
use crate::convert::ToPyObject;
6-
use crate::function::FuncArgs;
7+
use crate::function::{FuncArgs, KwArgs};
78
use crate::protocol::{BufferDescriptor, BufferMethods, PyBuffer, PyNumberMethods};
89
use crate::stdlib::ctypes::_ctypes::get_size;
910
use crate::types::{AsBuffer, AsNumber, Constructor};
10-
use crate::{AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine};
11-
use crossbeam_utils::atomic::AtomicCell;
11+
use crate::{AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine};
1212
use indexmap::IndexMap;
1313
use num_traits::ToPrimitive;
1414
use rustpython_common::lock::PyRwLock;
@@ -18,6 +18,8 @@ use std::fmt::Debug;
1818
#[pyclass(name = "PyCStructType", base = PyType, module = "_ctypes")]
1919
#[derive(Debug)]
2020
pub struct PyCStructType {
21+
#[allow(dead_code)]
22+
pub base: PyType,
2123
#[allow(dead_code)]
2224
pub stg_info: StgInfo,
2325
}
@@ -26,22 +28,34 @@ impl Constructor for PyCStructType {
2628
type Args = FuncArgs;
2729

2830
fn py_new(metatype: &Py<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Self> {
29-
// 1. Create the new class using PyType::py_new
30-
let new_class_payload = crate::builtins::type_::PyType::py_new(metatype, args.clone(), vm)?;
31-
let new_class = new_class_payload.into_ref_with_type(vm, metatype.to_owned())?;
32-
33-
// 2. Process _fields_ if defined on the new class
34-
let new_type = new_class.to_owned();
35-
36-
// Only process _fields_ if defined directly on this class (not inherited)
37-
if let Some(fields_attr) = new_type.get_direct_attr(vm.ctx.intern_str("_fields_")) {
38-
Self::process_fields(&new_type, fields_attr, vm)?;
39-
}
31+
// Create the base PyType - py_new returns the payload only
32+
let base = crate::builtins::type_::PyType::py_new(metatype, args, vm)?;
4033

4134
Ok(PyCStructType {
35+
base,
4236
stg_info: StgInfo::default(),
4337
})
4438
}
39+
40+
fn py_new_ref(
41+
metatype: PyTypeRef,
42+
args: FuncArgs,
43+
vm: &VirtualMachine,
44+
) -> PyResult<PyRef<Self>> {
45+
let payload = Self::py_new(&metatype, args, vm)?;
46+
let struct_metatype = PyCStructType::static_type();
47+
let typ_ref = payload.into_ref_with_type(vm, struct_metatype.to_owned())?;
48+
49+
// Finalize heap type (register subclass, member descriptors, etc.)
50+
let type_ref: PyTypeRef = typ_ref
51+
.as_object()
52+
.to_owned()
53+
.downcast()
54+
.expect("metaclass should downcast to PyType");
55+
PyType::finalize_heap_type(&type_ref, KwArgs::default(), vm)?;
56+
57+
Ok(typ_ref)
58+
}
4559
}
4660

4761
#[pyclass(flags(BASETYPE), with(AsNumber, Constructor))]
@@ -166,19 +180,7 @@ impl PyCStructType {
166180

167181
// Calculate element size from the Structure type
168182
let element_size = size_of(cls.clone().into(), vm)?;
169-
170-
let total_size = element_size
171-
.checked_mul(n as usize)
172-
.ok_or_else(|| vm.new_overflow_error("array size too large".to_owned()))?;
173-
let mut stg_info = super::util::StgInfo::new(total_size, element_size);
174-
stg_info.length = n as usize;
175-
Ok(PyCArrayType {
176-
stg_info,
177-
typ: PyRwLock::new(cls.clone().into()),
178-
length: AtomicCell::new(n as usize),
179-
element_size: AtomicCell::new(element_size),
180-
}
181-
.to_pyobject(vm))
183+
PyCArrayType::create_array_type(cls.clone().into(), n as usize, element_size, &cls, vm)
182184
}
183185
}
184186

0 commit comments

Comments
 (0)