more pointer implementation

fix import

add more classes

ctypes overhall

updates

fix build

fix warnings, pass test

fix panic on improper library load

test on macos

formatting

tmp

minor updates
This commit is contained in:
Ashwin Naren authored and Jeong YunWon committed 2025-11-28 23:27:24 +09:00
1 parent 0e6e256f8e
commit f37ea52565
9 files changed
+494 -164

No files matched your search

+10 -1
View File
@@ -2,11 +2,14 @@
pub(crate) mod array;
pub(crate) mod base;
pub(crate) mod field;
pub(crate) mod function;
pub(crate) mod library;
pub(crate) mod pointer;
pub(crate) mod structure;
pub(crate) mod thunk;
pub(crate) mod union;
pub(crate) mod util;
use crate::builtins::PyModule;
use crate::class::PyClassImpl;
@@ -17,14 +20,18 @@ pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py<PyModule>) {
let ctx = &vm.ctx;
PyCSimpleType::make_class(ctx);
array::PyCArrayType::make_class(ctx);
field::PyCFieldType::make_class(ctx);
pointer::PyCPointerType::make_class(ctx);
extend_module!(vm, module, {
"_CData" => PyCData::make_class(ctx),
"_SimpleCData" => PyCSimple::make_class(ctx),
"Array" => array::PyCArray::make_class(ctx),
"CField" => field::PyCField::make_class(ctx),
"CFuncPtr" => function::PyCFuncPtr::make_class(ctx),
"_Pointer" => pointer::PyCPointer::make_class(ctx),
"_pointer_type_cache" => ctx.new_dict(),
"Structure" => structure::PyCStructure::make_class(ctx),
"CThunkObject" => thunk::PyCThunk::make_class(ctx),
"Union" => union::PyCUnion::make_class(ctx),
})
}
@@ -207,7 +214,9 @@ pub(crate) mod _ctypes {
// TODO: load_flags
let cache = library::libcache();
let mut cache_write = cache.write();
let (id, _) = cache_write.get_or_insert_lib(&name, vm).unwrap();
let (id, _) = cache_write
.get_or_insert_lib(&name, vm)
.map_err(|e| vm.new_os_error(e.to_string()))?;
Ok(id)
}
+1
View File
@@ -106,6 +106,7 @@ impl PyCArray {
}
impl PyCArray {
#[allow(unused)]
pub fn to_arg(&self, _vm: &VirtualMachine) -> PyResult<libffi::middle::Arg> {
let value = self.value.read();
let py_bytes = value.downcast_ref::<PyBytes>().unwrap();
+11 -11
View File
@@ -276,25 +276,25 @@ impl PyCSimple {
let value = unsafe { (*self.value.as_ptr()).clone() };
if let Ok(i) = value.try_int(vm) {
let i = i.as_bigint();
if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u8().as_raw_ptr()) {
return i.to_u8().map(|r: u8| libffi::middle::Arg::new(&r));
return if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u8().as_raw_ptr()) {
i.to_u8().map(|r: u8| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i8().as_raw_ptr()) {
return i.to_i8().map(|r: i8| libffi::middle::Arg::new(&r));
i.to_i8().map(|r: i8| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u16().as_raw_ptr()) {
return i.to_u16().map(|r: u16| libffi::middle::Arg::new(&r));
i.to_u16().map(|r: u16| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i16().as_raw_ptr()) {
return i.to_i16().map(|r: i16| libffi::middle::Arg::new(&r));
i.to_i16().map(|r: i16| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u32().as_raw_ptr()) {
return i.to_u32().map(|r: u32| libffi::middle::Arg::new(&r));
i.to_u32().map(|r: u32| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i32().as_raw_ptr()) {
return i.to_i32().map(|r: i32| libffi::middle::Arg::new(&r));
i.to_i32().map(|r: i32| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u64().as_raw_ptr()) {
return i.to_u64().map(|r: u64| libffi::middle::Arg::new(&r));
i.to_u64().map(|r: u64| libffi::middle::Arg::new(&r))
} else if std::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i64().as_raw_ptr()) {
return i.to_i64().map(|r: i64| libffi::middle::Arg::new(&r));
i.to_i64().map(|r: i64| libffi::middle::Arg::new(&r))
} else {
return None;
}
None
};
}
if let Ok(_f) = value.try_float(vm) {
todo!();
+134
View File
@@ -0,0 +1,134 @@
use crate::builtins::PyType;
use crate::builtins::PyTypeRef;
use crate::stdlib::ctypes::PyCData;
use crate::types::Constructor;
use crate::types::Representable;
use crate::{Py, PyResult, VirtualMachine};
#[pyclass(name = "PyCFieldType", base = PyType, module = "_ctypes")]
#[derive(PyPayload, Debug)]
pub struct PyCFieldType {
pub(super) inner: PyCField,
}
#[pyclass]
impl PyCFieldType {}
#[pyclass(
name = "CField",
base = PyCData,
metaclass = "PyCFieldType",
module = "_ctypes"
)]
#[derive(Debug, PyPayload)]
pub struct PyCField {
byte_offset: usize,
byte_size: usize,
#[allow(unused)]
index: usize,
proto: PyTypeRef,
anonymous: bool,
bitfield_size: bool,
bit_offset: u8,
name: String,
}
impl Representable for PyCField {
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
let tp_name = zelf.proto.name().to_string();
if zelf.bitfield_size != false {
Ok(format!(
"<{} type={}, ofs={byte_offset}, bit_size={bitfield_size}, bit_offset={bit_offset}",
zelf.name,
tp_name,
byte_offset = zelf.byte_offset,
bitfield_size = zelf.bitfield_size,
bit_offset = zelf.bit_offset
))
} else {
Ok(format!(
"<{} type={tp_name}, ofs={}, size={}",
zelf.name, zelf.byte_offset, zelf.byte_size
))
}
}
}
#[derive(Debug, FromArgs)]
pub struct PyCFieldConstructorArgs {
// PyObject *name, PyObject *proto,
// Py_ssize_t byte_size, Py_ssize_t byte_offset,
// Py_ssize_t index, int _internal_use,
// PyObject *bit_size_obj, PyObject *bit_offset_obj
}
impl Constructor for PyCField {
type Args = PyCFieldConstructorArgs;
fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult {
Err(vm.new_type_error("Cannot instantiate a PyCField".to_string()))
}
}
#[pyclass(flags(BASETYPE, IMMUTABLETYPE), with(Constructor, Representable))]
impl PyCField {
#[pygetset]
fn size(&self) -> usize {
self.byte_size
}
#[pygetset]
fn bit_size(&self) -> bool {
self.bitfield_size
}
#[pygetset]
fn is_bitfield(&self) -> bool {
self.bitfield_size
}
#[pygetset]
fn is_anonymous(&self) -> bool {
self.anonymous
}
#[pygetset]
fn name(&self) -> String {
self.name.clone()
}
#[pygetset(name = "type")]
fn type_(&self) -> PyTypeRef {
self.proto.clone()
}
#[pygetset]
fn offset(&self) -> usize {
self.byte_offset
}
#[pygetset]
fn byte_offset(&self) -> usize {
self.byte_offset
}
#[pygetset]
fn byte_size(&self) -> usize {
self.byte_size
}
#[pygetset]
fn bit_offset(&self) -> u8 {
self.bit_offset
}
}
#[inline(always)]
pub const fn low_bit(offset: usize) -> usize {
offset & 0xFFFF
}
#[inline(always)]
pub const fn high_bit(offset: usize) -> usize {
offset >> 16
}
+246 -146
View File
@@ -1,142 +1,117 @@
// spell-checker:disable
use crate::builtins::{PyStr, PyTupleRef, PyTypeRef};
use crate::builtins::{PyNone, PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef};
use crate::convert::ToPyObject;
use crate::function::FuncArgs;
use crate::stdlib::ctypes::PyCData;
use crate::stdlib::ctypes::array::PyCArray;
use crate::stdlib::ctypes::base::{PyCSimple, ffi_type_from_str};
use crate::types::Representable;
use crate::types::{Callable, Constructor};
use crate::{Py, PyObjectRef, PyResult, VirtualMachine};
use crate::{AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine};
use crossbeam_utils::atomic::AtomicCell;
use libffi::middle::{Arg, Cif, CodePtr, Type};
use libloading::Symbol;
use num_traits::ToPrimitive;
use rustpython_common::lock::PyRwLock;
use std::ffi::CString;
use std::ffi::{self, CString, c_void};
use std::fmt::Debug;
// https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
#[derive(Debug)]
pub struct Function {
args: Vec<Type>,
// TODO: no protection from use-after-free
pointer: CodePtr,
cif: Cif,
}
unsafe impl Send for Function {}
unsafe impl Sync for Function {}
// See also: https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
type FP = unsafe extern "C" fn();
impl Function {
pub unsafe fn load(
library: &libloading::Library,
function: &str,
args: &[PyObjectRef],
ret_type: &Option<PyTypeRef>,
vm: &VirtualMachine,
) -> PyResult<Self> {
// map each arg to a PyCSimple
let args = args
.iter()
.map(|arg| {
if let Some(arg) = arg.downcast_ref::<PyCSimple>() {
let converted = ffi_type_from_str(&arg._type_);
return match converted {
Some(t) => Ok(t),
None => Err(vm.new_type_error("Invalid type")), // TODO: add type name
};
}
if let Some(arg) = arg.downcast_ref::<PyCArray>() {
let t = arg.typ.read();
let ty_attributes = t.attributes.read();
let ty_pystr = ty_attributes
.get(vm.ctx.intern_str("_type_"))
.ok_or_else(|| vm.new_type_error("Expected a ctypes simple type"))?;
let ty_str = ty_pystr
.downcast_ref::<PyStr>()
.ok_or_else(|| vm.new_type_error("Expected a ctypes simple type"))?
.to_string();
let converted = ffi_type_from_str(&ty_str);
match converted {
Some(_t) => {
// TODO: Use
Ok(Type::void())
}
None => Err(vm.new_type_error("Invalid type")), // TODO: add type name
}
} else {
Err(vm.new_type_error("Expected a ctypes simple type"))
}
})
.collect::<PyResult<Vec<Type>>>()?;
let c_function_name = CString::new(function)
.map_err(|_| vm.new_value_error("Function name contains null bytes"))?;
let pointer: Symbol<'_, FP> = unsafe {
library
.get(c_function_name.as_bytes())
.map_err(|err| err.to_string())
.map_err(|err| vm.new_attribute_error(err))?
};
let code_ptr = CodePtr(*pointer as *mut _);
let return_type = match ret_type {
// TODO: Fix this
Some(_t) => {
return Err(vm.new_not_implemented_error("Return type not implemented"));
}
None => Type::c_int(),
};
let cif = Cif::new(args.clone(), return_type);
Ok(Function {
args,
cif,
pointer: code_ptr,
})
pub trait ArgumentType {
fn to_ffi_type(&self, vm: &VirtualMachine) -> PyResult<Type>;
fn convert_object(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<Arg>;
}
impl ArgumentType for PyTypeRef {
fn to_ffi_type(&self, vm: &VirtualMachine) -> PyResult<Type> {
let typ = self
.get_class_attr(vm.ctx.intern_str("_type_"))
.ok_or(vm.new_type_error("Unsupported argument type".to_string()))?;
let typ = typ
.downcast_ref::<PyStr>()
.ok_or(vm.new_type_error("Unsupported argument type".to_string()))?;
let typ = typ.to_string();
let typ = typ.as_str();
let converted_typ = ffi_type_from_str(typ);
if let Some(typ) = converted_typ {
Ok(typ)
} else {
Err(vm.new_type_error(format!("Unsupported argument type: {}", typ)))
}
}
pub unsafe fn call(
fn convert_object(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<Arg> {
// if self.fast_isinstance::<PyCArray>(vm) {
// let array = value.downcast::<PyCArray>()?;
// return Ok(Arg::from(array.as_ptr()));
// }
if let Ok(simple) = value.downcast::<PyCSimple>() {
let typ = ArgumentType::to_ffi_type(self, vm)?;
let arg = simple
.to_arg(typ, vm)
.ok_or(vm.new_type_error("Unsupported argument type".to_string()))?;
return Ok(arg);
}
Err(vm.new_type_error("Unsupported argument type".to_string()))
}
}
pub trait ReturnType {
fn to_ffi_type(&self) -> Option<Type>;
fn from_ffi_type(
&self,
args: Vec<PyObjectRef>,
value: *mut ffi::c_void,
vm: &VirtualMachine,
) -> PyResult<PyObjectRef> {
let args = args
.into_iter()
.enumerate()
.map(|(count, arg)| {
// none type check
if let Some(d) = arg.downcast_ref::<PyCSimple>() {
return Ok(d.to_arg(self.args[count].clone(), vm).unwrap());
}
if let Some(d) = arg.downcast_ref::<PyCArray>() {
return Ok(d.to_arg(vm).unwrap());
}
Err(vm.new_type_error("Expected a ctypes simple type"))
})
.collect::<PyResult<Vec<Arg>>>()?;
// TODO: FIX return
let result: i32 = unsafe { self.cif.call(self.pointer, &args) };
Ok(vm.ctx.new_int(result).into())
) -> PyResult<Option<PyObjectRef>>;
}
impl ReturnType for PyTypeRef {
fn to_ffi_type(&self) -> Option<Type> {
ffi_type_from_str(self.name().to_string().as_str())
}
fn from_ffi_type(
&self,
_value: *mut ffi::c_void,
_vm: &VirtualMachine,
) -> PyResult<Option<PyObjectRef>> {
todo!()
}
}
impl ReturnType for PyNone {
fn to_ffi_type(&self) -> Option<Type> {
ffi_type_from_str("void")
}
fn from_ffi_type(
&self,
_value: *mut ffi::c_void,
_vm: &VirtualMachine,
) -> PyResult<Option<PyObjectRef>> {
Ok(None)
}
}
#[pyclass(module = "_ctypes", name = "CFuncPtr", base = PyCData)]
#[derive(PyPayload)]
pub struct PyCFuncPtr {
pub name: PyRwLock<String>,
pub _flags_: AtomicCell<u32>,
// FIXME(arihant2math): This shouldn't be an option, setting the default as the none type should work
// This is a workaround for now and I'll fix it later
pub _restype_: PyRwLock<Option<PyTypeRef>>,
pub name: PyRwLock<Option<String>>,
pub ptr: PyRwLock<Option<CodePtr>>,
pub needs_free: AtomicCell<bool>,
pub arg_types: PyRwLock<Option<Vec<PyTypeRef>>>,
pub res_type: PyRwLock<Option<PyObjectRef>>,
pub _flags_: AtomicCell<i32>,
pub handler: PyObjectRef,
}
impl Debug for PyCFuncPtr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PyCFuncPtr")
.field("name", &self.name)
.field("flags", &self._flags_)
.finish()
}
}
@@ -156,10 +131,43 @@ impl Constructor for PyCFuncPtr {
.nth(1)
.ok_or(vm.new_type_error("Expected a tuple with at least 2 elements"))?
.clone();
let handle = handler.try_int(vm);
let handle = match handle {
Ok(handle) => handle.as_bigint().clone(),
Err(_) => handler
.get_attr("_handle", vm)?
.try_int(vm)?
.as_bigint()
.clone(),
};
let library_cache = crate::stdlib::ctypes::library::libcache().read();
let library = library_cache
.get_lib(
handle
.to_usize()
.ok_or(vm.new_value_error("Invalid handle".to_string()))?,
)
.ok_or_else(|| vm.new_value_error("Library not found".to_string()))?;
let inner_lib = library.lib.lock();
let terminated = format!("{}\0", &name);
let code_ptr = if let Some(lib) = &*inner_lib {
let pointer: Symbol<'_, FP> = unsafe {
lib.get(terminated.as_bytes())
.map_err(|err| err.to_string())
.map_err(|err| vm.new_attribute_error(err))?
};
Some(CodePtr(*pointer as *mut _))
} else {
None
};
Ok(Self {
ptr: PyRwLock::new(code_ptr),
needs_free: AtomicCell::new(false),
arg_types: PyRwLock::new(None),
_flags_: AtomicCell::new(0),
name: PyRwLock::new(name),
_restype_: PyRwLock::new(None),
res_type: PyRwLock::new(None),
name: PyRwLock::new(Some(name)),
handler,
}
.to_pyobject(vm))
@@ -169,53 +177,145 @@ impl Constructor for PyCFuncPtr {
impl Callable for PyCFuncPtr {
type Args = FuncArgs;
fn call(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult {
unsafe {
let handle = zelf.handler.get_attr("_handle", vm)?;
let handle = handle.try_int(vm)?.as_bigint().clone();
let library_cache = crate::stdlib::ctypes::library::libcache().read();
let library = library_cache
.get_lib(
handle
.to_usize()
.ok_or(vm.new_value_error("Invalid handle"))?,
)
.ok_or_else(|| vm.new_value_error("Library not found"))?;
let inner_lib = library.lib.lock();
let name = zelf.name.read();
let res_type = zelf._restype_.read();
let func = Function::load(
inner_lib
.as_ref()
.ok_or_else(|| vm.new_value_error("Library not found"))?,
&name,
&args.args,
&res_type,
vm,
)?;
func.call(args.args, vm)
// This is completely seperate from the C python implementation
// Cif init
let arg_types: Vec<_> = match zelf.arg_types.read().clone() {
Some(tys) => tys,
None => args
.args
.clone()
.into_iter()
.map(|a| a.class().as_object().to_pyobject(vm).downcast().unwrap())
.collect(),
};
let ffi_arg_types = arg_types
.clone()
.iter()
.map(|t| ArgumentType::to_ffi_type(t, vm))
.collect::<PyResult<Vec<_>>>()?;
let return_type = zelf.res_type.read();
let ffi_return_type = return_type
.as_ref()
.map(|t| ReturnType::to_ffi_type(&t.clone().downcast::<PyType>().unwrap()))
.flatten()
.unwrap_or_else(|| Type::i32());
let cif = Cif::new(ffi_arg_types, ffi_return_type);
// Call the function
let ffi_args = args
.args
.into_iter()
.enumerate()
.map(|(n, arg)| {
let arg_type = arg_types
.get(n)
.ok_or_else(|| vm.new_type_error("argument amount mismatch".to_string()))?;
arg_type.convert_object(arg, vm)
})
.collect::<Result<Vec<_>, _>>()?;
let pointer = zelf.ptr.read();
let code_ptr = pointer
.as_ref()
.ok_or_else(|| vm.new_type_error("Function pointer not set".to_string()))?;
let mut output: c_void = unsafe { cif.call(*code_ptr, &ffi_args) };
let return_type = return_type
.as_ref()
.map(|f| {
f.clone()
.downcast::<PyType>()
.unwrap()
.from_ffi_type(&mut output, vm)
.ok()
.flatten()
})
.unwrap_or_else(|| Some(vm.ctx.new_int(output as i32).as_object().to_pyobject(vm)));
if let Some(return_type) = return_type {
Ok(return_type)
} else {
Ok(vm.ctx.none())
}
}
}
#[pyclass(flags(BASETYPE), with(Callable, Constructor))]
impl Representable for PyCFuncPtr {
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
let index = zelf.ptr.read();
let index = index.map(|ptr| ptr.0 as usize).unwrap_or(0);
let type_name = zelf.class().name();
#[cfg(windows)]
{
let index = index - 0x1000;
return Ok(format!("<COM method offset {index:#x} {type_name}>"));
}
Ok(format!("<{type_name} object at {index:#x}>"))
}
}
// TODO: fix
unsafe impl Send for PyCFuncPtr {}
unsafe impl Sync for PyCFuncPtr {}
#[pyclass(flags(BASETYPE), with(Callable, Constructor, Representable))]
impl PyCFuncPtr {
#[pygetset(name = "_restype_")]
fn restype(&self) -> Option<PyObjectRef> {
self.res_type.read().as_ref().cloned()
}
#[pygetset(name = "_restype_", setter)]
fn set_restype(&self, restype: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
// has to be type, callable, or none
// TODO: Callable support
if vm.is_none(&restype) || restype.downcast_ref::<PyType>().is_some() {
*self.res_type.write() = Some(restype);
Ok(())
} else {
Err(vm.new_type_error("restype must be a type, a callable, or None".to_string()))
}
}
#[pygetset(name = "argtypes")]
fn argtypes(&self, vm: &VirtualMachine) -> PyTupleRef {
PyTuple::new_ref(
self.arg_types
.read()
.clone()
.unwrap_or_default()
.into_iter()
.map(|t| t.to_pyobject(vm))
.collect(),
&vm.ctx,
)
}
#[pygetset(name = "argtypes", setter)]
fn set_argtypes(&self, argtypes: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let none = vm.is_none(&argtypes);
if none {
*self.arg_types.write() = None;
Ok(())
} else {
let tuple = argtypes.downcast::<PyTuple>().unwrap();
*self.arg_types.write() = Some(
tuple
.iter()
.map(|obj| obj.clone().downcast::<PyType>().unwrap())
.collect::<Vec<_>>(),
);
Ok(())
}
}
#[pygetset]
fn __name__(&self) -> String {
fn __name__(&self) -> Option<String> {
self.name.read().clone()
}
#[pygetset(setter)]
fn set___name__(&self, name: String) {
*self.name.write() = name;
}
#[pygetset(name = "_restype_")]
fn restype(&self) -> Option<PyTypeRef> {
self._restype_.read().as_ref().cloned()
}
#[pygetset(name = "_restype_", setter)]
fn set_restype(&self, restype: PyTypeRef) {
*self._restype_.write() = Some(restype);
fn set___name__(&self, name: String) -> PyResult<()> {
*self.name.write() = Some(name);
// TODO: update handle and stuff
Ok(())
}
}
+38 -3
View File
@@ -1,5 +1,40 @@
#[pyclass(name = "Pointer", module = "_ctypes")]
pub struct PyCPointer {}
use rustpython_common::lock::PyRwLock;
use crate::builtins::PyType;
use crate::stdlib::ctypes::PyCData;
use crate::{PyObjectRef, PyResult};
#[pyclass(name = "PyCPointerType", base = PyType, module = "_ctypes")]
#[derive(PyPayload, Debug)]
pub struct PyCPointerType {
pub inner: PyCPointer,
}
#[pyclass]
impl PyCPointerType {}
#[pyclass(
name = "_Pointer",
base = PyCData,
metaclass = "PyCPointerType",
module = "_ctypes"
)]
#[derive(Debug, PyPayload)]
pub struct PyCPointer {
contents: PyRwLock<PyObjectRef>,
}
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
impl PyCPointer {}
impl PyCPointer {
// TODO: not correct
#[pygetset]
fn contents(&self) -> PyResult<PyObjectRef> {
let contents = self.contents.read().clone();
Ok(contents)
}
#[pygetset(setter)]
fn set_contents(&self, contents: PyObjectRef) -> PyResult<()> {
*self.contents.write() = contents;
Ok(())
}
}
+22
View File
@@ -0,0 +1,22 @@
//! Yes, really, this is not a typo.
// typedef struct {
// PyObject_VAR_HEAD
// ffi_closure *pcl_write; /* the C callable, writeable */
// void *pcl_exec; /* the C callable, executable */
// ffi_cif cif;
// int flags;
// PyObject *converters;
// PyObject *callable;
// PyObject *restype;
// SETFUNC setfunc;
// ffi_type *ffi_restype;
// ffi_type *atypes[1];
// } CThunkObject;
#[pyclass(name = "CThunkObject", module = "_ctypes")]
#[derive(Debug, PyPayload)]
pub struct PyCThunk {}
#[pyclass]
impl PyCThunk {}
+24
View File
@@ -0,0 +1,24 @@
use crate::PyObjectRef;
#[pyclass(name, module = "_ctypes")]
#[derive(Debug, PyPayload)]
pub struct StgInfo {
pub initialized: i32,
pub size: usize, // number of bytes
pub align: usize, // alignment requirements
pub length: usize, // number of fields
// ffi_type_pointer: ffi::ffi_type,
pub proto: PyObjectRef, // Only for Pointer/ArrayObject
pub setfunc: Option<PyObjectRef>, // Only for simple objects
pub getfunc: Option<PyObjectRef>, // Only for simple objects
pub paramfunc: Option<PyObjectRef>,
/* Following fields only used by PyCFuncPtrType_Type instances */
pub argtypes: Option<PyObjectRef>, // tuple of CDataObjects
pub converters: Option<PyObjectRef>, // tuple([t.from_param for t in argtypes])
pub restype: Option<PyObjectRef>, // CDataObject or NULL
pub checker: Option<PyObjectRef>,
pub module: Option<PyObjectRef>,
pub flags: i32, // calling convention and such
pub dict_final: u8,
}
+8 -3
View File
@@ -40,7 +40,6 @@ def create_string_buffer(init, size=None):
size = len(init) + 1
_sys.audit("ctypes.create_string_buffer", init, size)
buftype = c_char.__mul__(size)
print(type(c_char.__mul__(size)))
# buftype = c_char * size
buf = buftype()
buf.value = init
@@ -334,8 +333,14 @@ cdll = LibraryLoader(CDLL)
test_byte_array = create_string_buffer(b"Hello, World!\n")
assert test_byte_array._length_ == 15
if _os.name == "posix" or _sys.platform == "darwin":
pass
if _os.name == "posix":
if _sys.platform == "darwin":
libc = cdll.LoadLibrary("libc.dylib")
libc.rand()
i = c_int(1)
print("start srand")
print(libc.srand(i))
print(test_byte_array)
else:
import os