use crate::registry::RegistryInterface;
use std::{
marker::PhantomData,
mem::MaybeUninit,
ops::Deref,
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard, Weak},
};
pub type EntryId = u32;
pub struct Entry<T = ()> {
iface: Weak<RwLock<dyn RegistryInterface + 'static>>,
id: EntryId,
phantom: PhantomData<T>,
}
impl std::fmt::Debug for Entry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "E{:?}", self.id)
}
}
impl<T> Entry<T>
where
T: Send + Sync,
{
pub(crate) fn new(iface: Weak<RwLock<dyn RegistryInterface>>, id: EntryId) -> Self {
Self {
iface,
id,
phantom: PhantomData,
}
}
pub fn as_generic(self) -> Entry {
let maybe_uninit = MaybeUninit::new(self);
let ptr = maybe_uninit.as_ptr();
unsafe {
Entry {
iface: std::ptr::read(&(*ptr).iface),
id: std::ptr::read(&(*ptr).id),
phantom: PhantomData,
}
}
}
pub fn write(&self) -> Option<EntryWriteGuard<'_, T>> {
let registry = self.iface.upgrade()?;
let ptr = self.iface.as_ptr();
let reference = unsafe { &*ptr };
Some(EntryWriteGuard::<T> {
_registry: registry,
guard: reference.write().unwrap(),
entry_id: self.id,
phantom: PhantomData,
})
}
pub fn read(&self) -> Option<EntryReadGuard<'_, T>> {
let registry = self.iface.upgrade()?;
let ptr = self.iface.as_ptr();
let reference = unsafe { &*ptr };
Some(EntryReadGuard::<T> {
_registry: registry,
guard: reference.read().unwrap(),
entry_id: self.id,
phantom: PhantomData,
})
}
pub fn get_id(&self) -> EntryId {
self.id
}
pub unsafe fn leak(self) {
std::mem::forget(self);
}
}
impl<T> Drop for Entry<T> {
#[inline(always)]
fn drop(&mut self) {
if let Some(arc) = self.iface.upgrade() {
if let Ok(mut guard) = arc.write() {
guard.remove(self.id);
}
}
}
}
pub struct EntryWriteGuard<'a, T> {
_registry: Arc<RwLock<dyn RegistryInterface>>,
guard: RwLockWriteGuard<'a, dyn RegistryInterface + 'static>,
entry_id: EntryId,
phantom: PhantomData<T>,
}
impl<T: 'static> EntryWriteGuard<'_, T> {
pub fn get(&self) -> &T {
self.guard
.get(self.entry_id)
.expect("Entry not found in the Registry")
.downcast_ref::<T>()
.expect("Failed to downcast Entry")
}
pub fn get_mut(&mut self) -> &mut T {
self.guard
.get_mut(self.entry_id)
.expect("Entry not found in the Registry")
.downcast_mut::<T>()
.expect("Failed to downcast Entry")
}
}
pub struct EntryReadGuard<'a, T> {
_registry: Arc<RwLock<dyn RegistryInterface>>,
guard: RwLockReadGuard<'a, dyn RegistryInterface + 'static>,
entry_id: EntryId,
phantom: PhantomData<T>,
}
impl<'a, T: 'static> Deref for EntryReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.guard
.get(self.entry_id)
.expect("Entry not found in the Registry")
.downcast_ref::<T>()
.expect("Failed to downcast Entry")
}
}
impl<T: 'static> EntryReadGuard<'_, T> {
pub fn get(&self) -> &T {
self.guard
.get(self.entry_id)
.expect("Entry not found in the Registry")
.downcast_ref::<T>()
.expect("Failed to downcast Entry")
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test() {
assert_eq!(size_of::<Entry>(), 24);
assert_eq!(size_of::<EntryReadGuard<()>>(), 48);
}
}