Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
41b30de
metaclass support for #[pyclass] macro
youknowone Aug 7, 2021
b4a1b80
Initial ctypes module structure with dlopen and dlsym
rodrigocam Oct 29, 2020
b9ada0a
Refactoring ctypes module to a PyPy-like file tree
darleybarreto Oct 31, 2020
1fa7e80
Add __getattr__ to deal with attributes at runtime
rodrigocam Oct 31, 2020
b30dbae
Adding a very basic and initial implementation of _SimpleCData and Fu…
darleybarreto Nov 2, 2020
89587f0
Add PyFuncPtr tp_new from DLL and basic tp_call
rodrigocam Nov 3, 2020
b4ddf4d
Adding basic functions to call libffi-rs
darleybarreto Nov 4, 2020
9177473
Fix compile errors
rodrigocam Nov 5, 2020
14b08b9
Changing some pieces of SharedLibrary
darleybarreto Nov 7, 2020
8adf4dd
Fixing some ref problems in functions.rs
darleybarreto Nov 8, 2020
4341c97
Cahnge PyRc to PyRef in data cache
rodrigocam Nov 10, 2020
eb8541c
Fixing arg type casting
darleybarreto Nov 10, 2020
e38b0a8
Refactoring PyCFuncPtr
darleybarreto Nov 12, 2020
c2df5de
Moving dlsym to from_dll
darleybarreto Nov 12, 2020
fa6b19b
Adding proper *mut c_void casting
darleybarreto Nov 13, 2020
7d220c3
Adding 'reopen' lib
darleybarreto Nov 13, 2020
0a92095
Adding function call
darleybarreto Nov 13, 2020
8ceffd9
Fixing clippy warnings
darleybarreto Nov 14, 2020
4c585ab
Fixing dangling ref
darleybarreto Nov 15, 2020
b09ebe0
Starting primitive types impl
darleybarreto Nov 19, 2020
d7888f9
Adding metaclass
darleybarreto Nov 19, 2020
145afc7
Adding PyCDataMethods trait
darleybarreto Nov 21, 2020
aff291f
Adding default value for PySimpleType
darleybarreto Nov 22, 2020
d29c3bf
Adding some comments
darleybarreto Nov 23, 2020
6fdffab
Implement PySimpleType __init__
darleybarreto Nov 26, 2020
568c838
Modifying Buffer for PyCData
darleybarreto Nov 29, 2020
fb07e53
Adding methods for PyCDataMethods
darleybarreto Nov 30, 2020
6122e40
Adding PyCData_NewGetBuffer related code
darleybarreto Dec 4, 2020
6a4f881
Fixing small fixes
darleybarreto Dec 4, 2020
e2e0ac8
Testing PySimpleType basic functionalities
darleybarreto Dec 5, 2020
c1324ce
Refactoring SharedLibrary
darleybarreto Dec 5, 2020
3f40466
Fixing several bugs
darleybarreto Dec 5, 2020
3e52625
Fixing function call
darleybarreto Dec 6, 2020
3454751
Fixing more of function calls
darleybarreto Dec 6, 2020
0f25f4d
PySimpleType from_param initial commit
darleybarreto Dec 7, 2020
c4f27fb
Adding more methods to PySimpleType
darleybarreto Dec 7, 2020
b88e544
Minor fixes to get compiling on master
coolreader18 Dec 9, 2020
4ce1123
Use static_cell for libcache
coolreader18 Dec 13, 2020
e528fe7
Adding RawBuffer & reworking low level function call
darleybarreto Dec 19, 2020
420a67a
Small fixes
darleybarreto Dec 21, 2020
d656650
Initial commit for PyCArray
darleybarreto Dec 21, 2020
2a1f6d7
Reworking CData buffers
darleybarreto Dec 30, 2020
ed44269
Adding PyCArray setitem
darleybarreto Dec 31, 2020
4d2c678
Adding some helper functions and initial tests
darleybarreto Dec 31, 2020
2c440b3
Adding PyCArray's from_param
darleybarreto Jan 1, 2021
0b65e0d
Adding several changes to make some tests pass
darleybarreto Jan 2, 2021
7c529af
Fix build on master
youknowone Aug 6, 2021
fe01b1a
hide ctypes test
youknowone Aug 6, 2021
25e0403
clean up ctypes::array
youknowone Aug 7, 2021
efabe9b
skeleton PyCSimpleType
youknowone Aug 7, 2021
b79477a
submodule extension for ctypes::dll
youknowone Aug 7, 2021
2904015
Merge pull request #4 from youknowone/dll-submodule
darleybarreto Aug 7, 2021
66a91cb
Add all tests from CPython and PyPy
darleybarreto Aug 8, 2021
577c5ae
Add suggestions and bump dependencies
darleybarreto Aug 8, 2021
6eb0794
Starting to add Metas to primitive and array ctypes
darleybarreto Aug 8, 2021
5916218
Fixing some terribly wrong impls and bugs.
darleybarreto Aug 15, 2021
c2ba116
Fix compilation
darleybarreto Aug 21, 2021
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
Prev Previous commit
Next Next commit
Adding several changes to make some tests pass
  • Loading branch information
darleybarreto authored and youknowone committed Aug 7, 2021
commit 0b65e0d935e97413ed53978cab94c03b4f8c99e9
2 changes: 1 addition & 1 deletion Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,4 @@ def WinError(code=None, descr=None):
elif sizeof(kind) == 8: c_uint64 = kind
del(kind)

_reset_cache()
# _reset_cache()
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -177,37 +177,42 @@ def test_bad_subclass(self):
with self.assertRaises(AttributeError):
class T(Array):
pass
T()
with self.assertRaises(AttributeError):
class T(Array):
_type_ = c_int
T()
with self.assertRaises(AttributeError):
class T(Array):
_length_ = 13

T()
def test_bad_length(self):
with self.assertRaises(ValueError):
class T(Array):
_type_ = c_int
_length_ = - sys.maxsize * 2
T()
with self.assertRaises(ValueError):
class T(Array):
_type_ = c_int
_length_ = -1
T()
with self.assertRaises(TypeError):
class T(Array):
_type_ = c_int
_length_ = 1.87
T()
with self.assertRaises(OverflowError):
class T(Array):
_type_ = c_int
_length_ = sys.maxsize * 2

T()
def test_zero_length(self):
# _length_ can be zero.
class T(Array):
_type_ = c_int
_length_ = 0

T()
@unittest.skip("TODO: RUSTPYTHON, implrment Structure")
def test_empty_element_struct(self):
class EmptyStruct(Structure):
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
100 changes: 57 additions & 43 deletions vm/src/stdlib/ctypes/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ use crate::VirtualMachine;

use crate::stdlib::ctypes::basics::{
default_from_param, generic_get_buffer, get_size, BorrowValue as BorrowValueCData,
BorrowValueMut, PyCData, PyCDataFunctions, PyCDataMethods, RawBuffer,
BorrowValueMut, PyCData, PyCDataFunctions, PyCDataMethods, PyCDataSequenceMethods, RawBuffer,
};
use crate::stdlib::ctypes::pointer::PyCPointer;
use crate::stdlib::ctypes::primitive::PySimpleType;
use crate::stdlib::ctypes::primitive::{new_simple_type, PySimpleType};

macro_rules! byte_match_type {
Comment thread
youknowone marked this conversation as resolved.
Outdated
(
Expand Down Expand Up @@ -111,19 +111,24 @@ pub fn make_array_with_lenght(
length: usize,
vm: &VirtualMachine,
) -> PyResult<PyRef<PyCArray>> {
if let Ok(ref outer_type) = vm.get_attribute(cls.as_object().to_owned(), "_type_") {
if let Ok(_type_) = outer_type.clone().downcast_exact::<PySimpleType>(vm) {
let itemsize = get_size(_type_._type_.as_str());

Ok(PyCArray {
_type_,
_length_: length,
_buffer: PyRwLock::new(RawBuffer {
inner: Vec::with_capacity(length * itemsize).as_mut_ptr(),
size: length * itemsize,
}),
if let Some(outer_type) = cls.get_attr("_type_") {
Comment thread
youknowone marked this conversation as resolved.
Outdated
let length = length as usize;
if let Ok(_type_) = vm.get_attribute(outer_type.clone(), "_type_") {
let itemsize = get_size(_type_.downcast::<PyStr>().unwrap().to_string().as_str());

if length.checked_mul(itemsize).is_none() {
Err(vm.new_overflow_error("Array size too big".to_string()))
} else {
Comment thread
youknowone marked this conversation as resolved.
Outdated
Ok(PyCArray {
_type_: new_simple_type(Either::A(&outer_type), vm)?.into_ref(vm),
_length_: length,
_buffer: PyRwLock::new(RawBuffer {
inner: Vec::with_capacity(length * itemsize).as_mut_ptr(),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this line is safe. The new Vec will be removed right after this line and the given pointer will be a dangling pointer.

size: length * itemsize,
}),
}
.into_ref_with_type(vm, cls)?)
}
.into_ref_with_type(vm, cls)?)
} else {
Err(vm.new_type_error("_type_ must have storage info".to_string()))
}
Expand All @@ -140,7 +145,7 @@ fn set_array_value(
obj: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
if obj.clone().downcast::<PyCData>().is_err() {
if !obj.clone_class().issubclass(PyCData::static_type()) {
let value = PyCDataMethods::from_param(zelf._type_.clone(), obj, vm)?;

let v_buffer = try_buffer_from_object(vm, &value)?;
Expand Down Expand Up @@ -247,7 +252,7 @@ impl PyCDataMethods for PyCArray {
};
Comment thread
youknowone marked this conversation as resolved.
Outdated

if vm.obj_len(&value)? > zelf._length_ {
Err(vm.new_value_error("Invalid length".to_string()))
Err(vm.new_value_error("value has size greater than the array".to_string()))
} else if zelf._type_._type_.as_str() == "c"
&& value.clone().downcast_exact::<PyBytes>(vm).is_err()
{
Expand All @@ -266,13 +271,16 @@ impl PyCDataMethods for PyCArray {
Err(vm.new_type_error("Invalid type".to_string()))
}?;

PyCArray::init(zelf.clone(), value, vm)?;
PyCArray::init(zelf.clone(), OptionalArg::Present(value), vm)?;

default_from_param(zelf.clone_class(), zelf.as_object().clone(), vm)
}
}

#[pyimpl(flags(BASETYPE), with(BufferProtocol))]
#[pyimpl(
flags(BASETYPE),
with(BufferProtocol, PyCDataFunctions, PyCDataMethods)
)]
impl PyCArray {
#[pyslot]
fn tp_new(cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
Expand Down Expand Up @@ -304,31 +312,31 @@ impl PyCArray {
}

#[pymethod(magic)]
pub fn init(zelf: PyRef<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value_lenght = vm.obj_len(&value)?;

if value_lenght < zelf._length_ {
let value_vec: Vec<PyObjectRef> = vm.extract_elements(&value)?;
for (i, v) in value_vec.iter().enumerate() {
Self::setitem(zelf.clone(), Either::A(i as isize), v.clone(), vm)?
}
Ok(())
} else if value_lenght == zelf._length_ {
let py_slice = Either::B(
PySlice {
start: Some(vm.new_pyobj(0)),
stop: vm.new_pyobj(zelf._length_),
step: None,
pub fn init(zelf: PyRef<Self>, value: OptionalArg, vm: &VirtualMachine) -> PyResult<()> {
value.map_or(Ok(()), |value| {
let value_lenght = vm.obj_len(&value)?;
Comment thread
youknowone marked this conversation as resolved.
Outdated

if value_lenght < zelf._length_ {
let value_vec: Vec<PyObjectRef> = vm.extract_elements(&value)?;
for (i, v) in value_vec.iter().enumerate() {
Self::setitem(zelf.clone(), Either::A(i as isize), v.clone(), vm)?
}
.into_ref(vm),
);
Ok(())
} else if value_lenght == zelf._length_ {
let py_slice = Either::B(
PySlice {
start: Some(vm.new_pyobj(0)),
stop: vm.new_pyobj(zelf._length_),
step: None,
}
.into_ref(vm),
);

Self::setitem(zelf, py_slice, value, vm)
} else {
Err(vm.new_value_error(
"number of values is greater than the size of the array".to_string(),
))
}
Self::setitem(zelf, py_slice, value, vm)
} else {
Err(vm.new_value_error("value has size greater than the array".to_string()))
}
})
}

#[pyproperty(name = "value")]
Expand Down Expand Up @@ -502,8 +510,10 @@ impl PyCArray {

let res = match k_or_idx {
Either::A(idx) => {
if idx < 0 || idx as usize > zelf._length_ {
if idx < 0 {
Err(vm.new_index_error("invalid index".to_string()))
} else if idx as usize > zelf._length_ {
Err(vm.new_index_error("index out of bounds".to_string()))
} else {
let idx = idx as usize;
let buffer_slice = buffer_bytes[idx..idx + offset].as_ref();
Expand Down Expand Up @@ -548,8 +558,10 @@ impl PyCArray {

match k_or_idx {
Either::A(idx) => {
if idx < 0 || idx as usize > zelf._length_ {
if idx < 0 {
Err(vm.new_index_error("invalid index".to_string()))
} else if idx as usize > zelf._length_ {
Err(vm.new_index_error("index out of bounds".to_string()))
} else {
set_array_value(&zelf, &mut buffer_bytes, idx as usize, offset, obj, vm)
}
Expand Down Expand Up @@ -617,3 +629,5 @@ impl PyCDataFunctions for PyCArray {
.new_pyobj(unsafe { &*zelf.borrow_value().inner } as *const _ as *const usize as usize))
}
}

impl PyCDataSequenceMethods for PyCArray {}
88 changes: 50 additions & 38 deletions vm/src/stdlib/ctypes/basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ use crate::common::borrow::{BorrowedValue, BorrowedValueMut};
use crate::common::lock::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard};
use crate::function::OptionalArg;
use crate::pyobject::{
PyObjectRef, PyRef, PyResult, PyValue, StaticType, TryFromObject, TypeProtocol,
Either, PyObjectRef, PyRef, PyResult, PyValue, StaticType, TryFromObject, TypeProtocol,
};
use crate::slots::BufferProtocol;
use crate::VirtualMachine;

use crate::stdlib::ctypes::array::make_array_with_lenght;
use crate::stdlib::ctypes::dll::dlsym;
use crate::stdlib::ctypes::primitive::{new_simple_type, PySimpleType};

use crossbeam_utils::atomic::AtomicCell;

Expand Down Expand Up @@ -55,7 +56,7 @@ pub fn get_size(ty: &str) -> usize {
"f" => c_float
"d" | "g" => c_double
"?" | "B" => c_uchar
"P" | "z" | "Z" => c_void
"P" | "z" | "Z" => usize
)
}

Expand Down Expand Up @@ -445,50 +446,61 @@ impl PyCData {
pub fn setstate(zelf: PyRef<Self>) {}
}

pub fn sizeof_func(tp: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if tp.clone().downcast::<PyCData>().is_err() {
Err(vm.new_type_error(format!(
"sizeof() argument must be a ctypes instance, not {}",
tp.class().name
)))
} else {
let size_of_instances = vm.get_method(tp, "size_of_instances").unwrap();
vm.invoke(&size_of_instances?, ())
pub fn sizeof_func(tp: Either<PyTypeRef, PyObjectRef>, vm: &VirtualMachine) -> PyResult {
match tp {
Either::A(type_) if type_.issubclass(PySimpleType::static_type()) => {
let zelf = new_simple_type(Either::B(&type_), vm)?;
PyCDataFunctions::size_of_instances(zelf.into_ref(vm), vm)
}
Either::B(obj) if obj.has_class_attr("size_of_instances") => {
let size_of = vm.get_attribute(obj, "size_of_instances").unwrap();
vm.invoke(&size_of, ())
}
_ => Err(vm.new_type_error("this type has no size".to_string())),
}
}

pub fn alignment(tp: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if tp.clone().downcast::<PyCData>().is_err() {
Err(vm.new_type_error(format!(
"alignment() argument must be a ctypes instance, not {}",
tp.class().name
)))
} else {
let alignment_of_instances = vm.get_method(tp, "alignment_of_instances").unwrap();
vm.invoke(&alignment_of_instances?, ())
pub fn alignment(tp: Either<PyTypeRef, PyObjectRef>, vm: &VirtualMachine) -> PyResult {
match tp {
Either::A(type_) if type_.issubclass(PySimpleType::static_type()) => {
let zelf = new_simple_type(Either::B(&type_), vm)?;
PyCDataFunctions::alignment_of_instances(zelf.into_ref(vm), vm)
}
Either::B(obj) if obj.has_class_attr("alignment_of_instances") => {
let size_of = vm.get_attribute(obj, "alignment_of_instances").unwrap();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let size_of = vm.get_attribute(obj, "alignment_of_instances").unwrap();
let size_of = vm.get_attribute(obj, "alignment_of_instances")?;

is this unwrap() intended?

vm.invoke(&size_of, ())
}
_ => Err(vm.new_type_error("no alignment info".to_string())),
}
}

pub fn byref(tp: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if tp.clone().downcast::<PyCData>().is_err() {
Err(vm.new_type_error(format!(
"byref() argument must be a ctypes instance, not {}",
tp.class().name
)))
} else {
let ref_to = vm.get_method(tp, "ref_to").unwrap();
vm.invoke(&ref_to?, ())
}
//@TODO: Return a Pointer when Pointer implementation is ready
let class = tp.clone_class();

if class.issubclass(PyCData::static_type()) {
if let Some(ref_to) = vm.get_method(tp, "ref_to") {
return vm.invoke(&ref_to?, ());
}
};

Err(vm.new_type_error(format!(
"byref() argument must be a ctypes instance, not '{}'",
class.name
)))
}

pub fn addressof(tp: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if tp.clone().downcast::<PyCData>().is_err() {
Err(vm.new_type_error(format!(
"addressof() argument must be a ctypes instance, not {}",
tp.class().name
)))
} else {
let address_of = vm.get_method(tp, "address_of").unwrap();
vm.invoke(&address_of?, ())
}
let class = tp.clone_class();

if class.issubclass(PyCData::static_type()) {
if let Some(address_of) = vm.get_method(tp, "address_of") {
return vm.invoke(&address_of?, ());
}
};

Err(vm.new_type_error(format!(
"addressof() argument must be a ctypes instance, not '{}'",
class.name
)))
}
4 changes: 2 additions & 2 deletions vm/src/stdlib/ctypes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::pyobject::PyClassImpl;
use crate::pyobject::PyObjectRef;
use crate::pyobject::{PyClassImpl, PyObjectRef, PyValue};
use crate::VirtualMachine;

mod array;
Expand Down Expand Up @@ -37,6 +36,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {

"POINTER" => ctx.new_function(POINTER),
"pointer" => ctx.new_function(pointer_fn),
"_pointer_type_cache" => ctx.new_dict(),

"CFuncPtr" => PyCFuncPtr::make_class(ctx),
"_SimpleCData" => PySimpleType::make_class(ctx),
Expand Down
2 changes: 1 addition & 1 deletion vm/src/stdlib/ctypes/pointer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

use crate::builtins::PyTypeRef;
use crate::builtins::{PyDict, PyTypeRef};
use crate::pyobject::{PyObjectRef, PyValue, StaticType};
use crate::VirtualMachine;

Expand Down
Loading