From 6804b96078e513e018a7ff3eada74e343267f55f Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sat, 9 May 2026 16:27:04 +0800 Subject: [PATCH] feat: add object pool for cdylib --- Cargo.lock | 16 ++++++++ wfassoc-cdylib/Cargo.toml | 1 + wfassoc-cdylib/src/lib.rs | 10 +++-- wfassoc-cdylib/src/object_pool.rs | 65 ++++++++++++++++++++++++++++++ wfassoc-cdylib/src/string_cache.rs | 7 ++++ 5 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 wfassoc-cdylib/src/object_pool.rs diff --git a/Cargo.lock b/Cargo.lock index a296b0c..6442c8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -493,6 +493,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -664,6 +673,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -750,6 +765,7 @@ name = "wfassoc-cdylib" version = "0.1.0" dependencies = [ "cbindgen", + "slotmap", "thiserror", "wfassoc", ] diff --git a/wfassoc-cdylib/Cargo.toml b/wfassoc-cdylib/Cargo.toml index 7a15985..1187323 100644 --- a/wfassoc-cdylib/Cargo.toml +++ b/wfassoc-cdylib/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["cdylib"] [dependencies] thiserror = { workspace = true } wfassoc = { path="../wfassoc" } +slotmap = "1.1.1" [build-dependencies] cbindgen = "0.29.0" diff --git a/wfassoc-cdylib/src/lib.rs b/wfassoc-cdylib/src/lib.rs index 5046c90..91f308f 100644 --- a/wfassoc-cdylib/src/lib.rs +++ b/wfassoc-cdylib/src/lib.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::ffi::{CString, c_char}; use thiserror::Error as TeError; +mod object_pool; mod last_error; mod string_cache; mod wrapper; @@ -11,9 +12,12 @@ mod wrapper; /// Error occurs in this crate. #[derive(Debug, TeError)] enum Error { - /// Error occurs in wfassoc core. + /// Error when parsing Schema into Program. #[error("{0}")] - Core(#[from] wfassoc::Error), + ParseProgram(#[from] wfassoc::highlevel::ParseProgramError), + /// Error when operating Program. + #[error("{0}")] + Program(#[from] wfassoc::highlevel::ProgramError), #[error("error occurs when parsing into C/C++ string")] CastIntoCStr(#[from] std::ffi::NulError), @@ -48,7 +52,7 @@ pub extern "C" fn WFGetLastError() -> *const c_char { #[unsafe(no_mangle)] pub extern "C" fn WFHasPrivilege() -> bool { - wfassoc::utilities::has_privilege() + wfassoc::win32::utilities::has_privilege() } #[unsafe(no_mangle)] diff --git a/wfassoc-cdylib/src/object_pool.rs b/wfassoc-cdylib/src/object_pool.rs new file mode 100644 index 0000000..94048cf --- /dev/null +++ b/wfassoc-cdylib/src/object_pool.rs @@ -0,0 +1,65 @@ +//! When exporting resources for C interface, resource management and ownership are important things. +//! In this dynamic library, we hold all resources' ownership in Rust world, +//! and only expose a token for C code manipulation. +//! +//! We need to create a container for holding all resources and providing corresponding operations. +//! So we introduce [ObjectPool] in this module for this purpose. +use slotmap::{DefaultKey, Key, KeyData, SlotMap}; +use thiserror::Error as TeError; + +/// Error occurs when operating with [ObjectPool]. +#[derive(Debug, TeError)] +pub enum Error { + #[error("given token is not presented in object pool")] + NoSuchToken, +} + +/// The token for fetching obejct in [ObjectPool]. +pub type Token = u64; + +/// A pool for managing objects with unique tokens. +/// +/// It is highly suggested to use this pool with [std::sync::RwLock] guard. +pub struct ObjectPool { + objs: SlotMap, +} + +impl ObjectPool { + pub fn new() -> Self { + Self { + objs: SlotMap::new(), + } + } + + fn key_to_token(key: &DefaultKey) -> Token { + key.data().as_ffi() + } + + fn token_to_key(token: Token) -> DefaultKey { + DefaultKey::from(KeyData::from_ffi(token)) + } + + pub fn allocate(&mut self, value: T) -> Result { + let key = self.objs.insert(value); + Ok(Self::key_to_token(&key)) + } + + pub fn delete(&mut self, token: Token) -> Result<(), Error> { + match self.objs.remove(Self::token_to_key(token)) { + Some(_) => Ok(()), + None => Err(Error::NoSuchToken), + } + } + + pub fn get(&self, token: Token) -> Result<&T, Error> { + self.objs + .get(Self::token_to_key(token)) + .ok_or(Error::NoSuchToken) + } + + pub fn get_mut(&mut self, token: Token) -> Result<&mut T, Error> { + self.objs + .get_mut(Self::token_to_key(token)) + .ok_or(Error::NoSuchToken) + } +} diff --git a/wfassoc-cdylib/src/string_cache.rs b/wfassoc-cdylib/src/string_cache.rs index 81737fe..b74d1fa 100644 --- a/wfassoc-cdylib/src/string_cache.rs +++ b/wfassoc-cdylib/src/string_cache.rs @@ -50,3 +50,10 @@ pub fn set_string_cache(msg: &str) { pub fn get_string_cache() -> *const c_char { STRING_CACHE.with(|e| e.borrow().get_msg()) } + +/// Clear thread local string cache. +pub fn clear_string_cache() { + STRING_CACHE.with(|e| { + e.borrow_mut().clear_msg(); + }); +}