Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5d27774

Browse filesBrowse files
committed
Refactor of ctypes into module and more implementations
Adds sizeof and PyCSimple Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
1 parent 572f3ba commit 5d27774
Copy full SHA for 5d27774

File tree

2 files changed

+251
-15
lines changed
Filter options

2 files changed

+251
-15
lines changed

‎vm/src/stdlib/ctypes.rs

Copy file name to clipboardExpand all lines: vm/src/stdlib/ctypes.rs
+88-15Lines 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

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

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.