//! 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 free(&mut self, token: Token) -> Result<(), Error> { let _ = self.pop(token)?; Ok(()) } pub fn pop(&mut self, token: Token) -> Result { match self.objs.remove(Self::token_to_key(token)) { Some(obj) => Ok(obj), 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) } }