use crate::collections::{MpmcQueue, RawVec}; use super::connector::Connector; use std::ptr; use std::sync::RwLock; /// A kind of token that, once obtained, allows access to a container. struct ConnectorKey { index: u32, // of connector } struct ConnectorStore { connectors: RawVec<*mut Connector>, free: Vec, } impl ConnectorStore { fn with_capacity(capacity: usize) -> Self { Self{ connectors: RawVec::with_capacity(capacity), free: Vec::with_capacity(capacity), } } fn get_mut(&self, key: &ConnectorKey) -> &'static mut Connector { unsafe { let connector = self.connectors.get_mut(key.index as usize); debug_assert!(!connector.is_null()); return *connector as &mut _; } } fn create(&mut self, connector: Connector) -> ConnectorKey { let index; if self.free.is_empty() { let connector = Box::into_raw(Box::new(connector)); unsafe { // Cheating a bit here. Anyway, move to heap, store in list index = self.connectors.len(); self.connectors.push(connector); } } else { index = self.free.pop().unwrap(); unsafe { let target = self.connectors.get_mut(index); debug_assert!(!target.is_null()); ptr::write(*target, connector); } } return ConnectorKey{ index: index as u32 }; } fn destroy(&mut self, key: ConnectorKey) { unsafe { let connector = self.connectors.get_mut(key.index as usize); ptr::drop_in_place(*connector); // Note: but not deallocating! } self.free.push(key.index as usize); } } impl Drop for ConnectorStore { fn drop(&mut self) { for idx in 0..self.connectors.len() { unsafe { let memory = *self.connectors.get_mut(idx); let boxed = Box::from_raw(memory); // takes care of deallocation } } } } /// Global store of connectors, ports and queues that are used by the sceduler /// threads. The global store has the appearance of a thread-safe datatype, but /// one needs to be careful using it. /// /// The intention of this data structure is to enforce the rules: /// TODO: @docs pub struct GlobalStore { connector_queue: MpmcQueue, connectors: RwLock, } impl GlobalStore { pub fn new() -> Self { Self{ connector_queue: MpmcQueue::with_capacity(256), connectors: RwLock::new(ConnectorStore::with_capacity(256)), } } // Taking connectors out of global queue pub fn pop_key(&self) -> Option { return self.connector_queue.pop_front(); } pub fn push_key(&self, key: ConnectorKey) { self.connector_queue.push_back(key); } // Creating, retrieving and destroying connectors /// Retrieves a connector using the provided key. Note that the returned /// reference is not truly static, the `GlobalStore` needs to stay alive. pub fn get_connector(&self, key: &ConnectorKey) -> &'static mut Connector { let connectors = self.connectors.read().unwrap(); return connectors.get_mut(key); } /// Adds a connector to the global system. Will also queue it to run pub fn add_connector(&self, connector: Connector) { let key = { let mut connectors = self.connectors.write().unwrap(); connectors.create(connector) }; self.connector_queue.push_back(key); } /// Destroys a connector pub fn destroy_connector(&self, key: ConnectorKey) { let mut connectors = self.connectors.write().unwrap(); connectors.destroy(key); } }