Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d56e4f7

Browse files
committed
Refactor of ctypes into module and more implementations
Adds sizeof and PyCSimple Signed-off-by: Ashwin Naren <[email protected]>
1 parent 572f3ba commit d56e4f7

File tree

3 files changed

+250
-16
lines changed

3 files changed

+250
-16
lines changed

vm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ uname = "0.1.1"
100100
rustyline = { workspace = true }
101101
which = "6"
102102
errno = "0.3"
103+
widestring = { workspace = true }
103104

104105
[target.'cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))'.dependencies]
105106
num_cpus = "1.13.1"
106107

107108
[target.'cfg(windows)'.dependencies]
108109
junction = { workspace = true }
109110
schannel = { workspace = true }
110-
widestring = { workspace = true }
111111
winreg = "0.52"
112112

113113
[target.'cfg(windows)'.dependencies.windows]

vm/src/stdlib/ctypes.rs

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,99 @@
1-
pub(crate) use _ctypes::make_module;
1+
pub(crate) mod base;
2+
3+
use crate::builtins::PyModule;
4+
use crate::{PyRef, VirtualMachine};
5+
6+
pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
7+
let module = _ctypes::make_module(&vm);
8+
base::extend_module_nodes(&vm, &module);
9+
module
10+
}
211

312
#[pymodule]
4-
mod _ctypes {
5-
use crate::{common::lock::PyRwLock, PyObjectRef};
13+
pub(crate) mod _ctypes {
14+
use super::base::PyCSimple;
15+
use crate::builtins::PyTypeRef;
16+
use crate::class::StaticType;
17+
use crate::function::Either;
18+
use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
619
use crossbeam_utils::atomic::AtomicCell;
20+
use std::ffi::{
21+
c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong,
22+
c_ulonglong,
23+
};
24+
use std::mem;
25+
use widestring::WideChar;
726

8-
pub struct RawBuffer {
9-
#[allow(dead_code)]
10-
pub inner: Box<[u8]>,
11-
#[allow(dead_code)]
12-
pub size: usize,
27+
pub fn get_size(ty: &str) -> usize {
28+
match ty {
29+
"u" => mem::size_of::<WideChar>(),
30+
"c" | "b" => mem::size_of::<c_schar>(),
31+
"h" => mem::size_of::<c_short>(),
32+
"H" => mem::size_of::<c_short>(),
33+
"i" => mem::size_of::<c_int>(),
34+
"I" => mem::size_of::<c_uint>(),
35+
"l" => mem::size_of::<c_long>(),
36+
"q" => mem::size_of::<c_longlong>(),
37+
"L" => mem::size_of::<c_ulong>(),
38+
"Q" => mem::size_of::<c_ulonglong>(),
39+
"f" => mem::size_of::<c_float>(),
40+
"d" | "g" => mem::size_of::<c_double>(),
41+
"?" | "B" => mem::size_of::<c_uchar>(),
42+
"P" | "z" | "Z" => mem::size_of::<usize>(),
43+
_ => unreachable!(),
44+
}
1345
}
1446

15-
#[pyattr]
16-
#[pyclass(name = "_CData")]
17-
pub struct PyCData {
18-
_objects: AtomicCell<Vec<PyObjectRef>>,
19-
_buffer: PyRwLock<RawBuffer>,
47+
const SIMPLE_TYPE_CHARS: &str = "cbBhHiIlLdfguzZPqQ?";
48+
49+
pub fn new_simple_type(
50+
cls: Either<&PyObjectRef, &PyTypeRef>,
51+
vm: &VirtualMachine,
52+
) -> PyResult<PyCSimple> {
53+
let cls = match cls {
54+
Either::A(obj) => obj,
55+
Either::B(typ) => typ.as_object(),
56+
};
57+
58+
if let Ok(_type_) = cls.get_attr("_type_", vm) {
59+
if _type_.is_instance((&vm.ctx.types.str_type).as_ref(), vm)? {
60+
let tp_str = _type_.str(vm)?.to_string();
61+
62+
if tp_str.len() != 1 {
63+
Err(vm.new_value_error(
64+
format!("class must define a '_type_' attribute which must be a string of length 1, str: {tp_str}"),
65+
))
66+
} else if !SIMPLE_TYPE_CHARS.contains(tp_str.as_str()) {
67+
Err(vm.new_attribute_error(format!("class must define a '_type_' attribute which must be\n a single character string containing one of {SIMPLE_TYPE_CHARS}, currently it is {tp_str}.")))
68+
} else {
69+
Ok(PyCSimple {
70+
_type_: tp_str,
71+
_value: AtomicCell::new(vm.ctx.none()),
72+
})
73+
}
74+
} else {
75+
Err(vm.new_type_error("class must define a '_type_' string attribute".to_string()))
76+
}
77+
} else {
78+
Err(vm.new_attribute_error("class must define a '_type_' attribute".to_string()))
79+
}
2080
}
2181

22-
#[pyclass]
23-
impl PyCData {}
82+
#[pyfunction(name = "sizeof")]
83+
pub fn size_of(tp: Either<PyTypeRef, PyObjectRef>, vm: &VirtualMachine) -> PyResult<usize> {
84+
match tp {
85+
Either::A(type_) if type_.fast_issubclass(PyCSimple::static_type()) => {
86+
let zelf = new_simple_type(Either::B(&type_), vm)?;
87+
Ok(get_size(zelf._type_.as_str()))
88+
}
89+
Either::B(obj) if obj.has_attr("size_of_instances", vm)? => {
90+
let size_of_method = obj.get_attr("size_of_instances", vm)?;
91+
let size_of_return = size_of_method.call(vec![], vm)?;
92+
Ok(usize::try_from_object(vm, size_of_return)?)
93+
}
94+
_ => Err(vm.new_type_error("this type has no size".to_string())),
95+
}
96+
}
2497

2598
#[pyfunction]
2699
fn get_errno() -> i32 {

vm/src/stdlib/ctypes/base.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use crate::builtins::{PyByteArray, PyBytes, PyFloat, PyInt, PyModule, PyNone, PyStr};
2+
use crate::class::PyClassImpl;
3+
use crate::{Py, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
4+
use crossbeam_utils::atomic::AtomicCell;
5+
use num_traits::ToPrimitive;
6+
use rustpython_common::lock::PyRwLock;
7+
use std::fmt::Debug;
8+
9+
#[allow(dead_code)]
10+
fn set_primitive(_type_: &str, value: &PyObjectRef, vm: &VirtualMachine) -> PyResult {
11+
match _type_ {
12+
"c" => {
13+
if value
14+
.clone()
15+
.downcast_exact::<PyBytes>(vm)
16+
.map_or(false, |v| v.len() == 1)
17+
|| value
18+
.clone()
19+
.downcast_exact::<PyByteArray>(vm)
20+
.map_or(false, |v| v.borrow_buf().len() == 1)
21+
|| value
22+
.clone()
23+
.downcast_exact::<PyInt>(vm)
24+
.map_or(Ok(false), |v| {
25+
let n = v.as_bigint().to_i64();
26+
if let Some(n) = n {
27+
Ok(0 <= n && n <= 255)
28+
} else {
29+
Ok(false)
30+
}
31+
})?
32+
{
33+
Ok(value.clone())
34+
} else {
35+
Err(vm.new_type_error(
36+
"one character bytes, bytearray or integer expected".to_string(),
37+
))
38+
}
39+
}
40+
"u" => {
41+
if let Ok(b) = value.str(vm).map(|v| v.to_string().chars().count() == 1) {
42+
if b {
43+
Ok(value.clone())
44+
} else {
45+
Err(vm.new_type_error("one character unicode string expected".to_string()))
46+
}
47+
} else {
48+
Err(vm.new_type_error(format!(
49+
"unicode string expected instead of {} instance",
50+
value.class().name()
51+
)))
52+
}
53+
}
54+
"b" | "h" | "H" | "i" | "I" | "l" | "q" | "L" | "Q" => {
55+
if value.clone().downcast_exact::<PyInt>(vm).is_ok() {
56+
Ok(value.clone())
57+
} else {
58+
Err(vm.new_type_error(format!(
59+
"an integer is required (got type {})",
60+
value.class().name()
61+
)))
62+
}
63+
}
64+
"f" | "d" | "g" => {
65+
if value.clone().downcast_exact::<PyFloat>(vm).is_ok() {
66+
Ok(value.clone())
67+
} else {
68+
Err(vm.new_type_error(format!("must be real number, not {}", value.class().name())))
69+
}
70+
}
71+
"?" => Ok(PyObjectRef::from(
72+
vm.ctx.new_bool(value.clone().try_to_bool(vm)?),
73+
)),
74+
"B" => {
75+
if value.clone().downcast_exact::<PyInt>(vm).is_ok() {
76+
Ok(vm.new_pyobj(u8::try_from_object(vm, value.clone())?))
77+
} else {
78+
Err(vm.new_type_error(format!("int expected instead of {}", value.class().name())))
79+
}
80+
}
81+
"z" => {
82+
if value.clone().downcast_exact::<PyInt>(vm).is_ok()
83+
|| value.clone().downcast_exact::<PyBytes>(vm).is_ok()
84+
{
85+
Ok(value.clone())
86+
} else {
87+
Err(vm.new_type_error(format!(
88+
"bytes or integer address expected instead of {} instance",
89+
value.class().name()
90+
)))
91+
}
92+
}
93+
"Z" => {
94+
if value.clone().downcast_exact::<PyStr>(vm).is_ok() {
95+
Ok(value.clone())
96+
} else {
97+
Err(vm.new_type_error(format!(
98+
"unicode string or integer address expected instead of {} instance",
99+
value.class().name()
100+
)))
101+
}
102+
}
103+
_ => {
104+
// "P"
105+
if value.clone().downcast_exact::<PyInt>(vm).is_ok()
106+
|| value.clone().downcast_exact::<PyNone>(vm).is_ok()
107+
{
108+
Ok(value.clone())
109+
} else {
110+
Err(vm.new_type_error("cannot be converted to pointer".to_string()))
111+
}
112+
}
113+
}
114+
}
115+
116+
pub struct RawBuffer {
117+
#[allow(dead_code)]
118+
pub inner: Box<[u8]>,
119+
#[allow(dead_code)]
120+
pub size: usize,
121+
}
122+
123+
#[pyclass(name = "_CData", module = "_ctypes")]
124+
pub struct PyCData {
125+
_objects: AtomicCell<Vec<PyObjectRef>>,
126+
_buffer: PyRwLock<RawBuffer>,
127+
}
128+
129+
#[pyclass]
130+
impl PyCData {}
131+
132+
#[pyclass(
133+
name = "_SimpleCData",
134+
base = "PyCData",
135+
module = "_ctypes"
136+
// TODO: metaclass
137+
)]
138+
#[derive(PyPayload)]
139+
pub struct PyCSimple {
140+
pub _type_: String,
141+
pub _value: AtomicCell<PyObjectRef>,
142+
}
143+
144+
impl Debug for PyCSimple {
145+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146+
f.debug_struct("PyCSimple")
147+
.field("_type_", &self._type_)
148+
.finish()
149+
}
150+
}
151+
152+
#[pyclass(flags(BASETYPE))]
153+
impl PyCSimple {}
154+
155+
pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py<PyModule>) {
156+
let ctx = &vm.ctx;
157+
extend_module!(vm, module, {
158+
"_CData" => PyCData::make_class(ctx),
159+
"_SimpleCData" => PyCSimple::make_class(ctx),
160+
})
161+
}

0 commit comments

Comments
 (0)