pub(crate) mod plugin;
use std::{
any::{type_name, Any, TypeId},
borrow::Cow,
collections::BTreeMap,
sync::Arc,
};
pub trait Resource: Any + 'static + Send + Sync {
fn name(&self) -> Cow<'_, str> {
type_name::<Self>().into()
}
fn close(self: Arc<Self>) {}
}
impl dyn Resource {
#[inline(always)]
fn is<T: Resource>(&self) -> bool {
self.type_id() == TypeId::of::<T>()
}
#[inline(always)]
pub(crate) fn downcast_arc<'a, T: Resource>(self: &'a Arc<Self>) -> Option<&'a Arc<T>> {
if self.is::<T>() {
let ptr = self as *const Arc<_> as *const Arc<T>;
Some(unsafe { &*ptr })
} else {
None
}
}
}
pub type ResourceId = u32;
#[derive(Default)]
pub struct ResourceTable {
index: BTreeMap<ResourceId, Arc<dyn Resource>>,
}
impl ResourceTable {
fn new_random_rid() -> u32 {
let mut bytes = [0_u8; 4];
getrandom::fill(&mut bytes).expect("failed to get random bytes");
u32::from_ne_bytes(bytes)
}
pub fn add<T: Resource>(&mut self, resource: T) -> ResourceId {
self.add_arc(Arc::new(resource))
}
pub fn add_arc<T: Resource>(&mut self, resource: Arc<T>) -> ResourceId {
let resource = resource as Arc<dyn Resource>;
self.add_arc_dyn(resource)
}
pub fn add_arc_dyn(&mut self, resource: Arc<dyn Resource>) -> ResourceId {
let mut rid = Self::new_random_rid();
while self.index.contains_key(&rid) {
rid = Self::new_random_rid();
}
let removed_resource = self.index.insert(rid, resource);
assert!(removed_resource.is_none());
rid
}
pub fn has(&self, rid: ResourceId) -> bool {
self.index.contains_key(&rid)
}
pub fn get<T: Resource>(&self, rid: ResourceId) -> crate::Result<Arc<T>> {
self
.index
.get(&rid)
.and_then(|rc| rc.downcast_arc::<T>())
.cloned()
.ok_or_else(|| crate::Error::BadResourceId(rid))
}
pub fn get_any(&self, rid: ResourceId) -> crate::Result<Arc<dyn Resource>> {
self
.index
.get(&rid)
.ok_or_else(|| crate::Error::BadResourceId(rid))
.cloned()
}
pub fn replace<T: Resource>(&mut self, rid: ResourceId, resource: T) {
let result = self
.index
.insert(rid, Arc::new(resource) as Arc<dyn Resource>);
assert!(result.is_some());
}
pub fn take<T: Resource>(&mut self, rid: ResourceId) -> crate::Result<Arc<T>> {
let resource = self.get::<T>(rid)?;
self.index.remove(&rid);
Ok(resource)
}
pub fn take_any(&mut self, rid: ResourceId) -> crate::Result<Arc<dyn Resource>> {
self
.index
.remove(&rid)
.ok_or_else(|| crate::Error::BadResourceId(rid))
}
pub fn names(&self) -> impl Iterator<Item = (ResourceId, Cow<'_, str>)> {
self
.index
.iter()
.map(|(&id, resource)| (id, resource.name()))
}
pub fn close(&mut self, rid: ResourceId) -> crate::Result<()> {
self
.index
.remove(&rid)
.ok_or_else(|| crate::Error::BadResourceId(rid))
.map(|resource| resource.close())
}
pub(crate) fn clear(&mut self) {
self.index.clear()
}
}