Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
PyCStructure
  • Loading branch information
youknowone committed Nov 29, 2025
commit 4b52c56eee25bf24a178dde06ec47f3870aa84d5
59 changes: 55 additions & 4 deletions crates/vm/src/stdlib/ctypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py<PyModule>) {
array::PyCArrayType::make_class(ctx);
field::PyCFieldType::make_class(ctx);
pointer::PyCPointerType::make_class(ctx);
structure::PyCStructType::make_class(ctx);
extend_module!(vm, module, {
"_CData" => PyCData::make_class(ctx),
"_SimpleCData" => PyCSimple::make_class(ctx),
Expand All @@ -46,9 +47,10 @@ pub(crate) mod _ctypes {
use super::base::PyCSimple;
use crate::builtins::PyTypeRef;
use crate::class::StaticType;
use crate::convert::ToPyObject;
use crate::function::{Either, FuncArgs, OptionalArg};
use crate::stdlib::ctypes::library;
use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
use crate::{AsObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine};
use crossbeam_utils::atomic::AtomicCell;
use std::ffi::{
c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong,
Expand All @@ -57,6 +59,22 @@ pub(crate) mod _ctypes {
use std::mem;
use widestring::WideChar;

/// CArgObject - returned by byref()
#[pyclass(name = "CArgObject", module = "_ctypes", no_attr)]
#[derive(Debug, PyPayload)]
pub struct CArgObject {
pub obj: PyObjectRef,
pub offset: isize,
}

#[pyclass]
impl CArgObject {
#[pygetset]
fn _obj(&self) -> PyObjectRef {
self.obj.clone()
}
}

#[pyattr(name = "__version__")]
const __VERSION__: &str = "1.1.0";

Expand Down Expand Up @@ -322,9 +340,27 @@ pub(crate) mod _ctypes {
}

#[pyfunction]
fn byref(_args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
// TODO: RUSTPYTHON
Err(vm.new_value_error("not implemented"))
fn byref(obj: PyObjectRef, offset: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
use super::base::PyCData;
use crate::class::StaticType;

// Check if obj is a ctypes instance
if !obj.fast_isinstance(PyCData::static_type())
&& !obj.fast_isinstance(PyCSimple::static_type())
{
return Err(vm.new_type_error(
"byref() argument must be a ctypes instance, not 'int'".to_string(),
));
}

let offset_val = offset.unwrap_or(0);

// Create CArgObject to hold the reference
Ok(CArgObject {
obj,
offset: offset_val,
}
.to_pyobject(vm))
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[pyfunction]
Expand Down Expand Up @@ -380,6 +416,21 @@ pub(crate) mod _ctypes {
f as usize
}

#[pyattr]
fn _wstring_at_addr(_vm: &VirtualMachine) -> usize {
// Return address of wcsnlen or similar wide string function
#[cfg(not(target_os = "windows"))]
{
let f = libc::wcslen;
f as usize
}
#[cfg(target_os = "windows")]
{
// On Windows, use wcslen from ucrt
0
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[pyattr]
fn _cast_addr(_vm: &VirtualMachine) -> usize {
// TODO: RUSTPYTHON
Expand Down
50 changes: 47 additions & 3 deletions crates/vm/src/stdlib/ctypes/array.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use crate::builtins::PyBytes;
use crate::types::Callable;
use crate::convert::ToPyObject;
use crate::protocol::PyNumberMethods;
use crate::types::{AsNumber, Callable};
use crate::{Py, PyObjectRef, PyPayload};
use crate::{
PyResult, VirtualMachine,
builtins::{PyType, PyTypeRef},
types::Constructor,
};
use crossbeam_utils::atomic::AtomicCell;
use num_traits::ToPrimitive;
use rustpython_common::lock::PyRwLock;
use rustpython_vm::stdlib::ctypes::base::PyCData;

Expand Down Expand Up @@ -44,8 +47,49 @@ impl Constructor for PyCArrayType {
}
}

#[pyclass(flags(IMMUTABLETYPE), with(Callable, Constructor))]
impl PyCArrayType {}
#[pyclass(flags(IMMUTABLETYPE), with(Callable, Constructor, AsNumber))]
impl PyCArrayType {
#[pymethod]
fn __mul__(zelf: &Py<Self>, n: isize, vm: &VirtualMachine) -> PyResult {
if n < 0 {
return Err(vm.new_value_error(format!("Array length must be >= 0, not {n}")));
}
// Create a nested array type: (inner_type * inner_length) * n
// The new array's element type is the current array type
let inner_type = zelf.inner.typ.read().clone();
let inner_length = zelf.inner.length.load();

// Create a new array type where the element is the current array
Ok(PyCArrayType {
inner: PyCArray {
typ: PyRwLock::new(inner_type),
length: AtomicCell::new(inner_length * n as usize),
value: PyRwLock::new(vm.ctx.none()),
},
}
.to_pyobject(vm))
}
}

impl AsNumber for PyCArrayType {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
multiply: Some(|a, b, vm| {
let zelf = a
.downcast_ref::<PyCArrayType>()
.ok_or_else(|| vm.new_type_error("expected PyCArrayType".to_owned()))?;
let n = b
.try_index(vm)?
.as_bigint()
.to_isize()
.ok_or_else(|| vm.new_overflow_error("array size too large".to_owned()))?;
PyCArrayType::__mul__(zelf, n, vm)
}),
..PyNumberMethods::NOT_IMPLEMENTED
};
&AS_NUMBER
}
}

#[pyclass(
name = "Array",
Expand Down
Loading