_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:
Ashwin Naren
2025-02-19 17:50:10 -08:00
committed by GitHub
parent fa2acd7cde
commit e2b0fe4266
11 changed files with 424 additions and 95 deletions

124
Cargo.lock generated
View File

@@ -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",

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -0,0 +1,5 @@
#[pyclass(name = "Array", module = "_ctypes")]
pub struct PyCArray {}
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
impl PyCArray {}

View File

@@ -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(())
}
}

View 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 {}

View 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()))
}

View File

@@ -0,0 +1,5 @@
#[pyclass(name = "Pointer", module = "_ctypes")]
pub struct PyCPointer {}
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
impl PyCPointer {}

View File

@@ -0,0 +1,5 @@
#[pyclass(name = "Structure", module = "_ctypes")]
pub struct PyCStructure {}
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
impl PyCStructure {}

View File

@@ -0,0 +1,5 @@
#[pyclass(name = "Union", module = "_ctypes")]
pub struct PyCUnion {}
#[pyclass(flags(BASETYPE, IMMUTABLETYPE))]
impl PyCUnion {}