-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Ctypes implementation #2364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ctypes implementation #2364
Changes from 1 commit
41b30de
b4a1b80
b9ada0a
1fa7e80
b30dbae
89587f0
b4ddf4d
9177473
14b08b9
8adf4dd
4341c97
eb8541c
e38b0a8
c2df5de
fa6b19b
7d220c3
0a92095
8ceffd9
4c585ab
b09ebe0
d7888f9
145afc7
aff291f
d29c3bf
6fdffab
568c838
fb07e53
6122e40
6a4f881
e2e0ac8
c1324ce
3f40466
3e52625
3454751
0f25f4d
c4f27fb
b88e544
4ce1123
e528fe7
420a67a
d656650
2a1f6d7
ed44269
4d2c678
2c440b3
0b65e0d
7c529af
fe01b1a
25e0403
efabe9b
b79477a
2904015
66a91cb
577c5ae
6eb0794
5916218
c2ba116
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 { | ||
| ( | ||
|
|
@@ -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_") { | ||
|
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 { | ||
|
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(), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this line is safe. The new |
||
| 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())) | ||
| } | ||
|
|
@@ -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)?; | ||
|
|
@@ -247,7 +252,7 @@ impl PyCDataMethods for PyCArray { | |
| }; | ||
|
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() | ||
| { | ||
|
|
@@ -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>> { | ||
|
|
@@ -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)?; | ||
|
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")] | ||
|
|
@@ -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(); | ||
|
|
@@ -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) | ||
| } | ||
|
|
@@ -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 {} | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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; | ||||||
|
|
||||||
|
|
@@ -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 | ||||||
| ) | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -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(); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
is this |
||||||
| 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 | ||||||
| ))) | ||||||
| } | ||||||
Uh oh!
There was an error while loading. Please reload this page.