mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
@@ -2,10 +2,12 @@
|
||||
|
||||
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;
|
||||
|
||||
use crate::builtins::PyModule;
|
||||
@@ -17,14 +19,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 +213,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -218,11 +218,12 @@ impl Constructor for PyCSimple {
|
||||
_ => vm.ctx.none(), // "z" | "Z" | "P"
|
||||
}
|
||||
};
|
||||
Ok(PyCSimple {
|
||||
PyCSimple {
|
||||
_type_,
|
||||
value: AtomicCell::new(value),
|
||||
}
|
||||
.to_pyobject(vm))
|
||||
.into_ref_with_type(vm, cls)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,25 +277,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!();
|
||||
|
||||
125
crates/vm/src/stdlib/ctypes/field.rs
Normal file
125
crates/vm/src/stdlib/ctypes/field.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
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 {
|
||||
#[allow(dead_code)]
|
||||
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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,142 +1,120 @@
|
||||
// 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, 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>;
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
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>>,
|
||||
#[allow(dead_code)]
|
||||
pub needs_free: AtomicCell<bool>,
|
||||
pub arg_types: PyRwLock<Option<Vec<PyTypeRef>>>,
|
||||
pub res_type: PyRwLock<Option<PyObjectRef>>,
|
||||
pub _flags_: AtomicCell<i32>,
|
||||
#[allow(dead_code)]
|
||||
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 +134,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 +180,144 @@ 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()
|
||||
.and_then(|t| ReturnType::to_ffi_type(&t.clone().downcast::<PyType>().unwrap()))
|
||||
.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();
|
||||
if cfg!(windows) {
|
||||
let index = index - 0x1000;
|
||||
Ok(format!("<COM method offset {index:#x} {type_name}>"))
|
||||
} else {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
#[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 {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) 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
crates/vm/src/stdlib/ctypes/thunk.rs
Normal file
22
crates/vm/src/stdlib/ctypes/thunk.rs
Normal 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 {}
|
||||
@@ -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
|
||||
|
||||
@@ -343,9 +348,9 @@ else:
|
||||
libc.rand()
|
||||
i = c_int(1)
|
||||
print("start srand")
|
||||
print(libc.srand(i))
|
||||
print(test_byte_array)
|
||||
print(test_byte_array._type_)
|
||||
# print(libc.srand(i))
|
||||
# print(test_byte_array)
|
||||
# print(test_byte_array._type_)
|
||||
# print("start printf")
|
||||
# libc.printf(test_byte_array)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user