diff --git a/vm/src/stdlib/ctypes.rs b/vm/src/stdlib/ctypes.rs index 2580939b62..701094a375 100644 --- a/vm/src/stdlib/ctypes.rs +++ b/vm/src/stdlib/ctypes.rs @@ -214,6 +214,16 @@ pub(crate) mod _ctypes { } } + #[pyfunction] + fn addressof(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { + if obj.is_instance(PyCSimple::static_type().as_ref(), vm)? { + let simple = obj.downcast_ref::().unwrap(); + Ok(simple.value.as_ptr() as usize) + } else { + Err(vm.new_type_error("expected a ctypes instance".to_string())) + } + } + #[pyfunction] fn get_errno() -> i32 { errno::errno().0 diff --git a/vm/src/stdlib/ctypes/structure.rs b/vm/src/stdlib/ctypes/structure.rs index 13cca6c260..c6cf158953 100644 --- a/vm/src/stdlib/ctypes/structure.rs +++ b/vm/src/stdlib/ctypes/structure.rs @@ -1,5 +1,61 @@ +use crate::builtins::{PyList, PyStr, PyTuple, PyTypeRef}; +use crate::function::FuncArgs; +use crate::types::GetAttr; +use crate::{AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine}; +use rustpython_common::lock::PyRwLock; +use rustpython_vm::types::Constructor; +use std::collections::HashMap; +use std::fmt::Debug; + #[pyclass(name = "Structure", module = "_ctypes")] -pub struct PyCStructure {} +#[derive(PyPayload, Debug)] +pub struct PyCStructure { + #[allow(dead_code)] + field_data: PyRwLock>, + data: PyRwLock>, +} + +impl Constructor for PyCStructure { + type Args = FuncArgs; + + fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + let fields_attr = cls + .get_class_attr(vm.ctx.interned_str("_fields_").unwrap()) + .ok_or_else(|| { + vm.new_attribute_error("Structure must have a _fields_ attribute".to_string()) + })?; + // downcast into list + let fields = fields_attr.downcast_ref::().ok_or_else(|| { + vm.new_type_error("Structure _fields_ attribute must be a list".to_string()) + })?; + let fields = fields.borrow_vec(); + let mut field_data = HashMap::new(); + for field in fields.iter() { + let field = field + .downcast_ref::() + .ok_or_else(|| vm.new_type_error("Field must be a tuple".to_string()))?; + let name = field + .first() + .unwrap() + .downcast_ref::() + .ok_or_else(|| vm.new_type_error("Field name must be a string".to_string()))?; + let typ = field.get(1).unwrap().clone(); + field_data.insert(name.as_str().to_string(), typ); + } + todo!("Implement PyCStructure::py_new") + } +} + +impl GetAttr for PyCStructure { + fn getattro(zelf: &Py, name: &Py, vm: &VirtualMachine) -> PyResult { + let name = name.to_string(); + let data = zelf.data.read(); + match data.get(&name) { + Some(value) => Ok(value.clone()), + None => Err(vm.new_attribute_error(format!("No attribute named {}", name))), + } + } +} #[pyclass(flags(BASETYPE, IMMUTABLETYPE))] impl PyCStructure {}