mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
_ctypes pt. 2 (#5524)
* add __version__ * add more types/constants * shared library and ExternalLibs implementation * FreeLibrary for windows * fixed PyCSimple * LoadLibrary and FreeLibrary for non-windows * fault-tolerant float equality Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
This commit is contained in:
124
Cargo.lock
generated
124
Cargo.lock
generated
@@ -216,9 +216,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.13"
|
||||
version = "1.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
|
||||
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -645,9 +645,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
@@ -905,7 +905,7 @@ dependencies = [
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.52.0",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1028,9 +1028,9 @@ checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553"
|
||||
|
||||
[[package]]
|
||||
name = "lambert_w"
|
||||
version = "1.0.14"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b0c98033daa8d13aa2171722fd201bae337924189091f7988bdaff5301fa8c9"
|
||||
checksum = "45bf98425154bfe790a47b72ac452914f6df9ebfb202bc59e089e29db00258cf"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
@@ -1099,6 +1099,16 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.11"
|
||||
@@ -1408,9 +1418,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.70"
|
||||
version = "0.10.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
|
||||
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"cfg-if",
|
||||
@@ -1449,9 +1459,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.105"
|
||||
version = "0.9.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
|
||||
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1747,8 +1757,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.0",
|
||||
"zerocopy 0.8.17",
|
||||
"rand_core 0.9.1",
|
||||
"zerocopy 0.8.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1768,7 +1778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.0",
|
||||
"rand_core 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1782,12 +1792,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||
checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3"
|
||||
dependencies = [
|
||||
"getrandom 0.3.1",
|
||||
"zerocopy 0.8.17",
|
||||
"zerocopy 0.8.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2272,6 +2282,7 @@ dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"junction",
|
||||
"libc",
|
||||
"libloading",
|
||||
"log",
|
||||
"malachite-bigint",
|
||||
"memchr",
|
||||
@@ -2526,9 +2537,9 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -2554,15 +2565,15 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.27.0"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce1475c515a4f03a8a7129bb5228b81a781a86cb0b3fbbc19e1c556d491a401f"
|
||||
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.27.0"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9688894b43459159c82bfa5a5fa0435c19cbe3c9b427fa1dd7b1ce0c279b18a7"
|
||||
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -2781,9 +2792,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "ucd"
|
||||
@@ -2997,9 +3008,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.13.1"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0"
|
||||
checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
]
|
||||
@@ -3185,11 +3196,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.57.0"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core 0.57.0",
|
||||
"windows-core",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
@@ -3202,49 +3213,6 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.57.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
@@ -3479,11 +3447,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.17"
|
||||
version = "0.8.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713"
|
||||
checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.8.17",
|
||||
"zerocopy-derive 0.8.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3499,9 +3467,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.17"
|
||||
version = "0.8.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626"
|
||||
checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
import os as _os, sys as _sys
|
||||
|
||||
from _ctypes import sizeof
|
||||
from _ctypes import _SimpleCData
|
||||
from struct import calcsize as _calcsize
|
||||
|
||||
def create_string_buffer(init, size=None):
|
||||
"""create_string_buffer(aBytes) -> character array
|
||||
create_string_buffer(anInteger) -> character array
|
||||
create_string_buffer(aBytes, anInteger) -> character array
|
||||
"""
|
||||
if isinstance(init, bytes):
|
||||
if size is None:
|
||||
size = len(init)+1
|
||||
_sys.audit("ctypes.create_string_buffer", init, size)
|
||||
buftype = c_char * size
|
||||
buf = buftype()
|
||||
buf.value = init
|
||||
return buf
|
||||
elif isinstance(init, int):
|
||||
_sys.audit("ctypes.create_string_buffer", None, init)
|
||||
buftype = c_char * init
|
||||
buf = buftype()
|
||||
return buf
|
||||
raise TypeError(init)
|
||||
|
||||
def _check_size(typ, typecode=None):
|
||||
# Check if sizeof(ctypes_type) against struct.calcsize. This
|
||||
# should protect somewhat against a misconfigured libffi.
|
||||
@@ -103,3 +125,9 @@ _check_size(c_void_p)
|
||||
class c_bool(_SimpleCData):
|
||||
_type_ = "?"
|
||||
_check_size(c_bool)
|
||||
|
||||
i = c_int(42)
|
||||
f = c_float(3.14)
|
||||
# s = create_string_buffer(b'\000' * 32)
|
||||
assert i.value == 42
|
||||
assert abs(f.value - 3.14) < 1e-06
|
||||
|
||||
@@ -100,6 +100,7 @@ uname = "0.1.1"
|
||||
rustyline = { workspace = true }
|
||||
which = "6"
|
||||
errno = "0.3"
|
||||
libloading = "0.8"
|
||||
widestring = { workspace = true }
|
||||
|
||||
[target.'cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))'.dependencies]
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
pub(crate) mod array;
|
||||
pub(crate) mod base;
|
||||
pub(crate) mod function;
|
||||
pub(crate) mod library;
|
||||
pub(crate) mod pointer;
|
||||
pub(crate) mod structure;
|
||||
pub(crate) mod union;
|
||||
|
||||
use crate::builtins::PyModule;
|
||||
use crate::{PyRef, VirtualMachine};
|
||||
use crate::class::PyClassImpl;
|
||||
use crate::stdlib::ctypes::base::{PyCData, PyCSimple, PySimpleMeta};
|
||||
use crate::{Py, PyRef, VirtualMachine};
|
||||
|
||||
pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py<PyModule>) {
|
||||
let ctx = &vm.ctx;
|
||||
PySimpleMeta::make_class(ctx);
|
||||
extend_module!(vm, module, {
|
||||
"_CData" => PyCData::make_class(ctx),
|
||||
"_SimpleCData" => PyCSimple::make_class(ctx),
|
||||
"Array" => array::PyCArray::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),
|
||||
"Union" => union::PyCUnion::make_class(ctx),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
|
||||
let module = _ctypes::make_module(vm);
|
||||
base::extend_module_nodes(vm, &module);
|
||||
extend_module_nodes(vm, &module);
|
||||
module
|
||||
}
|
||||
|
||||
@@ -15,6 +38,7 @@ pub(crate) mod _ctypes {
|
||||
use crate::builtins::PyTypeRef;
|
||||
use crate::class::StaticType;
|
||||
use crate::function::Either;
|
||||
use crate::stdlib::ctypes::library;
|
||||
use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use std::ffi::{
|
||||
@@ -24,6 +48,57 @@ pub(crate) mod _ctypes {
|
||||
use std::mem;
|
||||
use widestring::WideChar;
|
||||
|
||||
#[pyattr(name = "__version__")]
|
||||
const __VERSION__: &str = "1.1.0";
|
||||
|
||||
// TODO: get properly
|
||||
#[pyattr(name = "RTLD_LOCAL")]
|
||||
const RTLD_LOCAL: i32 = 0;
|
||||
|
||||
// TODO: get properly
|
||||
#[pyattr(name = "RTLD_GLOBAL")]
|
||||
const RTLD_GLOBAL: i32 = 0;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[pyattr(name = "SIZEOF_TIME_T")]
|
||||
pub const SIZEOF_TIME_T: usize = 8;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[pyattr(name = "SIZEOF_TIME_T")]
|
||||
pub const SIZEOF_TIME_T: usize = 4;
|
||||
|
||||
#[pyattr(name = "CTYPES_MAX_ARGCOUNT")]
|
||||
pub const CTYPES_MAX_ARGCOUNT: usize = 1024;
|
||||
|
||||
#[pyattr]
|
||||
pub const FUNCFLAG_STDCALL: u32 = 0x0;
|
||||
#[pyattr]
|
||||
pub const FUNCFLAG_CDECL: u32 = 0x1;
|
||||
#[pyattr]
|
||||
pub const FUNCFLAG_HRESULT: u32 = 0x2;
|
||||
#[pyattr]
|
||||
pub const FUNCFLAG_PYTHONAPI: u32 = 0x4;
|
||||
#[pyattr]
|
||||
pub const FUNCFLAG_USE_ERRNO: u32 = 0x8;
|
||||
#[pyattr]
|
||||
pub const FUNCFLAG_USE_LASTERROR: u32 = 0x10;
|
||||
|
||||
#[pyattr]
|
||||
pub const TYPEFLAG_ISPOINTER: u32 = 0x100;
|
||||
#[pyattr]
|
||||
pub const TYPEFLAG_HASPOINTER: u32 = 0x200;
|
||||
|
||||
#[pyattr]
|
||||
pub const DICTFLAG_FINAL: u32 = 0x1000;
|
||||
|
||||
#[pyattr(once)]
|
||||
fn error(vm: &VirtualMachine) -> PyTypeRef {
|
||||
vm.ctx.new_exception_type(
|
||||
"_ctypes",
|
||||
"ArgumentError",
|
||||
Some(vec![vm.ctx.exceptions.exception_type.to_owned()]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_size(ty: &str) -> usize {
|
||||
match ty {
|
||||
"u" => mem::size_of::<WideChar>(),
|
||||
@@ -68,7 +143,7 @@ pub(crate) mod _ctypes {
|
||||
} else {
|
||||
Ok(PyCSimple {
|
||||
_type_: tp_str,
|
||||
_value: AtomicCell::new(vm.ctx.none()),
|
||||
value: AtomicCell::new(vm.ctx.none()),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@@ -95,6 +170,41 @@ pub(crate) mod _ctypes {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction(name = "LoadLibrary")]
|
||||
fn load_library(name: String, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
// TODO: audit functions first
|
||||
let cache = library::libcache();
|
||||
let mut cache_write = cache.write();
|
||||
let lib_ref = cache_write.get_or_insert_lib(&name, vm).unwrap();
|
||||
Ok(lib_ref.get_pointer())
|
||||
}
|
||||
|
||||
#[pyfunction(name = "FreeLibrary")]
|
||||
fn free_library(handle: usize) -> PyResult<()> {
|
||||
let cache = library::libcache();
|
||||
let mut cache_write = cache.write();
|
||||
cache_write.drop_lib(handle);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyfunction(name = "POINTER")]
|
||||
pub fn pointer(_cls: PyTypeRef) {}
|
||||
|
||||
#[pyfunction]
|
||||
pub fn pointer_fn(_inst: PyObjectRef) {}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[pyfunction(name = "_check_HRESULT")]
|
||||
pub fn check_hresult(_self: PyObjectRef, hr: i32, _vm: &VirtualMachine) -> PyResult<i32> {
|
||||
// TODO: fixme
|
||||
if hr < 0 {
|
||||
// vm.ctx.new_windows_error(hr)
|
||||
todo!();
|
||||
} else {
|
||||
Ok(hr)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_errno() -> i32 {
|
||||
errno::errno().0
|
||||
|
||||
5
vm/src/stdlib/ctypes/array.rs
Normal file
5
vm/src/stdlib/ctypes/array.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
#[pyclass(name = "Array", module = "_ctypes")]
|
||||
pub struct PyCArray {}
|
||||
|
||||
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
|
||||
impl PyCArray {}
|
||||
@@ -1,6 +1,10 @@
|
||||
use crate::builtins::{PyBytes, PyFloat, PyInt, PyModule, PyNone, PyStr};
|
||||
use crate::class::PyClassImpl;
|
||||
use crate::{Py, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
|
||||
use crate::builtins::PyType;
|
||||
use crate::builtins::{PyBytes, PyFloat, PyInt, PyNone, PyStr, PyTypeRef};
|
||||
use crate::convert::ToPyObject;
|
||||
use crate::function::{Either, OptionalArg};
|
||||
use crate::stdlib::ctypes::_ctypes::new_simple_type;
|
||||
use crate::types::Constructor;
|
||||
use crate::{AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use num_traits::ToPrimitive;
|
||||
use rustpython_common::lock::PyRwLock;
|
||||
@@ -129,16 +133,32 @@ pub struct PyCData {
|
||||
#[pyclass]
|
||||
impl PyCData {}
|
||||
|
||||
#[pyclass(module = "_ctypes", name = "PyCSimpleType", base = "PyType")]
|
||||
pub struct PySimpleMeta {}
|
||||
|
||||
#[pyclass(flags(BASETYPE))]
|
||||
impl PySimpleMeta {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
#[pymethod]
|
||||
fn new(cls: PyTypeRef, _: OptionalArg, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyObjectRef::from(
|
||||
new_simple_type(Either::B(&cls), vm)?
|
||||
.into_ref_with_type(vm, cls)?
|
||||
.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
name = "_SimpleCData",
|
||||
base = "PyCData",
|
||||
module = "_ctypes"
|
||||
// TODO: metaclass
|
||||
module = "_ctypes",
|
||||
metaclass = "PySimpleMeta"
|
||||
)]
|
||||
#[derive(PyPayload)]
|
||||
pub struct PyCSimple {
|
||||
pub _type_: String,
|
||||
pub _value: AtomicCell<PyObjectRef>,
|
||||
pub value: AtomicCell<PyObjectRef>,
|
||||
}
|
||||
|
||||
impl Debug for PyCSimple {
|
||||
@@ -149,13 +169,56 @@ impl Debug for PyCSimple {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(flags(BASETYPE))]
|
||||
impl PyCSimple {}
|
||||
impl Constructor for PyCSimple {
|
||||
type Args = (OptionalArg,);
|
||||
|
||||
pub fn extend_module_nodes(vm: &VirtualMachine, module: &Py<PyModule>) {
|
||||
let ctx = &vm.ctx;
|
||||
extend_module!(vm, module, {
|
||||
"_CData" => PyCData::make_class(ctx),
|
||||
"_SimpleCData" => PyCSimple::make_class(ctx),
|
||||
})
|
||||
fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
|
||||
let attributes = cls.get_attributes();
|
||||
let _type_ = attributes
|
||||
.iter()
|
||||
.find(|(&k, _)| k.to_object().str(vm).unwrap().to_string() == *"_type_")
|
||||
.unwrap()
|
||||
.1
|
||||
.str(vm)?
|
||||
.to_string();
|
||||
let value = if let Some(ref v) = args.0.into_option() {
|
||||
set_primitive(_type_.as_str(), v, vm)?
|
||||
} else {
|
||||
match _type_.as_str() {
|
||||
"c" | "u" => PyObjectRef::from(vm.ctx.new_bytes(vec![0])),
|
||||
"b" | "B" | "h" | "H" | "i" | "I" | "l" | "q" | "L" | "Q" => {
|
||||
PyObjectRef::from(vm.ctx.new_int(0))
|
||||
}
|
||||
"f" | "d" | "g" => PyObjectRef::from(vm.ctx.new_float(0.0)),
|
||||
"?" => PyObjectRef::from(vm.ctx.new_bool(false)),
|
||||
_ => vm.ctx.none(), // "z" | "Z" | "P"
|
||||
}
|
||||
};
|
||||
Ok(PyCSimple {
|
||||
_type_,
|
||||
value: AtomicCell::new(value),
|
||||
}
|
||||
.to_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(flags(BASETYPE), with(Constructor))]
|
||||
impl PyCSimple {
|
||||
#[pygetset(name = "value")]
|
||||
pub fn value(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
let zelf: &Py<Self> = instance
|
||||
.downcast_ref()
|
||||
.ok_or_else(|| vm.new_type_error("cannot get value of instance".to_string()))?;
|
||||
Ok(unsafe { (*zelf.value.as_ptr()).clone() })
|
||||
}
|
||||
|
||||
#[pygetset(name = "value", setter)]
|
||||
fn set_value(instance: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let zelf: PyRef<Self> = instance
|
||||
.downcast()
|
||||
.map_err(|_| vm.new_type_error("cannot set value of instance".to_string()))?;
|
||||
let content = set_primitive(zelf._type_.as_str(), &value, vm)?;
|
||||
zelf.value.store(content);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
24
vm/src/stdlib/ctypes/function.rs
Normal file
24
vm/src/stdlib/ctypes/function.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use crate::stdlib::ctypes::PyCData;
|
||||
use crate::PyObjectRef;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use rustpython_common::lock::PyRwLock;
|
||||
use std::ffi::c_void;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Function {
|
||||
_pointer: *mut c_void,
|
||||
_arguments: Vec<()>,
|
||||
_return_type: Box<()>,
|
||||
}
|
||||
|
||||
#[pyclass(module = "_ctypes", name = "CFuncPtr", base = "PyCData")]
|
||||
pub struct PyCFuncPtr {
|
||||
pub _name_: String,
|
||||
pub _argtypes_: AtomicCell<Vec<PyObjectRef>>,
|
||||
pub _restype_: AtomicCell<PyObjectRef>,
|
||||
_handle: PyObjectRef,
|
||||
_f: PyRwLock<Function>,
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
impl PyCFuncPtr {}
|
||||
115
vm/src/stdlib/ctypes/library.rs
Normal file
115
vm/src/stdlib/ctypes/library.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use crate::VirtualMachine;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use libloading::Library;
|
||||
use rustpython_common::lock::PyRwLock;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::c_void;
|
||||
use std::fmt;
|
||||
use std::ptr::null;
|
||||
|
||||
pub struct SharedLibrary {
|
||||
lib: AtomicCell<Option<Library>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for SharedLibrary {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "SharedLibrary")
|
||||
}
|
||||
}
|
||||
|
||||
impl SharedLibrary {
|
||||
pub fn new(name: &str) -> Result<SharedLibrary, libloading::Error> {
|
||||
Ok(SharedLibrary {
|
||||
lib: AtomicCell::new(Some(unsafe { Library::new(name)? })),
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_sym(&self, name: &str) -> Result<*mut c_void, String> {
|
||||
if let Some(inner) = unsafe { &*self.lib.as_ptr() } {
|
||||
unsafe {
|
||||
inner
|
||||
.get(name.as_bytes())
|
||||
.map(|f: libloading::Symbol<*mut c_void>| *f)
|
||||
.map_err(|err| err.to_string())
|
||||
}
|
||||
} else {
|
||||
Err("The library has been closed".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer(&self) -> usize {
|
||||
if let Some(l) = unsafe { &*self.lib.as_ptr() } {
|
||||
l as *const Library as usize
|
||||
} else {
|
||||
null::<c_void>() as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self) -> bool {
|
||||
unsafe { &*self.lib.as_ptr() }.is_none()
|
||||
}
|
||||
|
||||
pub fn close(&self) {
|
||||
let old = self.lib.take();
|
||||
self.lib.store(None);
|
||||
drop(old);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SharedLibrary {
|
||||
fn drop(&mut self) {
|
||||
self.close();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExternalLibs {
|
||||
libraries: HashMap<usize, SharedLibrary>,
|
||||
}
|
||||
|
||||
impl ExternalLibs {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
libraries: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_lib(&self, key: usize) -> Option<&SharedLibrary> {
|
||||
self.libraries.get(&key)
|
||||
}
|
||||
|
||||
pub fn get_or_insert_lib(
|
||||
&mut self,
|
||||
library_path: &str,
|
||||
_vm: &VirtualMachine,
|
||||
) -> Result<&SharedLibrary, libloading::Error> {
|
||||
let nlib = SharedLibrary::new(library_path)?;
|
||||
let key = nlib.get_pointer();
|
||||
|
||||
match self.libraries.get(&key) {
|
||||
Some(l) => {
|
||||
if l.is_closed() {
|
||||
self.libraries.insert(key, nlib);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.libraries.insert(key, nlib);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(self.libraries.get(&key).unwrap())
|
||||
}
|
||||
|
||||
pub fn drop_lib(&mut self, key: usize) {
|
||||
self.libraries.remove(&key);
|
||||
}
|
||||
}
|
||||
|
||||
rustpython_common::static_cell! {
|
||||
static LIBCACHE: PyRwLock<ExternalLibs>;
|
||||
}
|
||||
|
||||
pub fn libcache() -> &'static PyRwLock<ExternalLibs> {
|
||||
LIBCACHE.get_or_init(|| PyRwLock::new(ExternalLibs::new()))
|
||||
}
|
||||
5
vm/src/stdlib/ctypes/pointer.rs
Normal file
5
vm/src/stdlib/ctypes/pointer.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
#[pyclass(name = "Pointer", module = "_ctypes")]
|
||||
pub struct PyCPointer {}
|
||||
|
||||
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
|
||||
impl PyCPointer {}
|
||||
5
vm/src/stdlib/ctypes/structure.rs
Normal file
5
vm/src/stdlib/ctypes/structure.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
#[pyclass(name = "Structure", module = "_ctypes")]
|
||||
pub struct PyCStructure {}
|
||||
|
||||
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
|
||||
impl PyCStructure {}
|
||||
5
vm/src/stdlib/ctypes/union.rs
Normal file
5
vm/src/stdlib/ctypes/union.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
#[pyclass(name = "Union", module = "_ctypes")]
|
||||
pub struct PyCUnion {}
|
||||
|
||||
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
|
||||
impl PyCUnion {}
|
||||
Reference in New Issue
Block a user