use std::any::type_name;
use std::any::Any;
use std::any::TypeId;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::iter::Iterator;
use std::rc::Rc;
pub trait Resource: Any + 'static {
fn name(&self) -> Cow<str> {
type_name::<Self>().into()
}
fn close(self: Rc<Self>) {}
}
impl dyn Resource {
#[inline(always)]
fn is<T: Resource>(&self) -> bool {
self.type_id() == TypeId::of::<T>()
}
#[inline(always)]
#[allow(clippy::needless_lifetimes)]
pub fn downcast_rc<'a, T: Resource>(self: &'a Rc<Self>) -> Option<&'a Rc<T>> {
if self.is::<T>() {
let ptr = self as *const Rc<_> as *const Rc<T>;
Some(unsafe { &*ptr })
} else {
None
}
}
}
pub type ResourceId = u32;
#[derive(Default)]
pub struct ResourceTable {
index: BTreeMap<ResourceId, Rc<dyn Resource>>,
next_rid: ResourceId,
}
impl ResourceTable {
pub fn add<T: Resource>(&mut self, resource: T) -> ResourceId {
self.add_rc(Rc::new(resource))
}
pub fn add_rc<T: Resource>(&mut self, resource: Rc<T>) -> ResourceId {
let resource = resource as Rc<dyn Resource>;
let rid = self.next_rid;
let removed_resource = self.index.insert(rid, resource);
assert!(removed_resource.is_none());
self.next_rid += 1;
rid
}
pub fn has(&self, rid: ResourceId) -> bool {
self.index.contains_key(&rid)
}
pub fn get<T: Resource>(&self, rid: ResourceId) -> Option<Rc<T>> {
self
.index
.get(&rid)
.and_then(|rc| rc.downcast_rc::<T>())
.map(Clone::clone)
}
pub fn get_any(&self, rid: ResourceId) -> Option<Rc<dyn Resource>> {
self.index.get(&rid).map(Clone::clone)
}
pub fn take<T: Resource>(&mut self, rid: ResourceId) -> Option<Rc<T>> {
let resource = self.get::<T>(rid)?;
self.index.remove(&rid);
Some(resource)
}
pub fn take_any(&mut self, rid: ResourceId) -> Option<Rc<dyn Resource>> {
self.index.remove(&rid)
}
pub fn close(&mut self, rid: ResourceId) -> Option<()> {
self.index.remove(&rid).map(|resource| resource.close())
}
pub fn names(&self) -> impl Iterator<Item = (ResourceId, Cow<str>)> {
self
.index
.iter()
.map(|(&id, resource)| (id, resource.name()))
}
}