pub use self::data::{Read, ReadExpect, Write, WriteExpect};
pub use self::entry::Entry;
pub use self::setup::{DefaultProvider, PanicHandler, SetupHandler};
use std::any::TypeId;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use fxhash::FxHashMap;
use mopa::Any;
use self::entry::create_entry;
use cell::{Ref, RefMut, TrustCell};
mod data;
mod entry;
#[macro_use]
mod setup;
pub struct Fetch<'a, T: 'a> {
inner: Ref<'a, Box<Resource>>,
phantom: PhantomData<&'a T>,
}
impl<'a, T> Deref for Fetch<'a, T>
where
T: Resource,
{
type Target = T;
fn deref(&self) -> &T {
unsafe { self.inner.downcast_ref_unchecked() }
}
}
pub struct FetchMut<'a, T: 'a> {
inner: RefMut<'a, Box<Resource>>,
phantom: PhantomData<&'a mut T>,
}
impl<'a, T> Deref for FetchMut<'a, T>
where
T: Resource,
{
type Target = T;
fn deref(&self) -> &T {
unsafe { self.inner.downcast_ref_unchecked() }
}
}
impl<'a, T> DerefMut for FetchMut<'a, T>
where
T: Resource,
{
fn deref_mut(&mut self) -> &mut T {
unsafe { self.inner.downcast_mut_unchecked() }
}
}
pub trait Resource: Any + Send + Sync + 'static {}
mopafy!(Resource);
impl<T> Resource for T
where
T: Any + Send + Sync,
{
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ResourceId(pub TypeId);
impl ResourceId {
pub fn new<T: Resource>() -> Self {
ResourceId(TypeId::of::<T>())
}
}
#[derive(Default)]
pub struct Resources {
resources: FxHashMap<ResourceId, TrustCell<Box<Resource>>>,
}
impl Resources {
pub fn new() -> Self {
Default::default()
}
pub fn insert<R>(&mut self, r: R)
where
R: Resource,
{
self.resources
.insert(ResourceId::new::<R>(), TrustCell::new(Box::new(r)));
}
pub fn has_value<R>(&self) -> bool
where
R: Resource,
{
self.has_value_raw(ResourceId::new::<R>())
}
pub fn has_value_raw(&self, id: ResourceId) -> bool {
self.resources.contains_key(&id)
}
pub fn entry<R>(&mut self) -> Entry<R>
where
R: Resource,
{
create_entry(self.resources.entry(ResourceId::new::<R>()))
}
pub fn fetch<T>(&self) -> Fetch<T>
where
T: Resource,
{
self.try_fetch().unwrap_or_else(|| fetch_panic!())
}
pub fn try_fetch<T>(&self) -> Option<Fetch<T>>
where
T: Resource,
{
let res_id = ResourceId::new::<T>();
self.resources.get(&res_id).map(|r| Fetch {
inner: r.borrow(),
phantom: PhantomData,
})
}
pub fn fetch_mut<T>(&self) -> FetchMut<T>
where
T: Resource,
{
self.try_fetch_mut().unwrap_or_else(|| fetch_panic!())
}
pub fn try_fetch_mut<T>(&self) -> Option<FetchMut<T>>
where
T: Resource,
{
let res_id = ResourceId::new::<T>();
self.resources.get(&res_id).map(|r| FetchMut {
inner: r.borrow_mut(),
phantom: PhantomData,
})
}
pub fn try_fetch_internal(&self, id: TypeId) -> Option<&TrustCell<Box<Resource>>> {
self.resources.get(&ResourceId(id))
}
pub fn get_mut<T: Resource>(&mut self) -> Option<&mut T> {
self.get_mut_raw(TypeId::of::<T>())
.map(|res| unsafe { res.downcast_mut_unchecked() })
}
pub fn get_mut_raw(&mut self, id: TypeId) -> Option<&mut Resource> {
self.resources
.get_mut(&ResourceId(id))
.map(TrustCell::get_mut)
.map(Box::as_mut)
}
}
#[cfg(test)]
mod tests {
use super::*;
use {RunNow, System, SystemData};
#[derive(Default)]
struct Res;
#[test]
fn fetch_aspects() {
assert_eq!(Read::<Res>::reads(), vec![ResourceId::new::<Res>()]);
assert_eq!(Read::<Res>::writes(), vec![]);
let mut res = Resources::new();
res.insert(Res);
<Read<Res> as SystemData>::fetch(&res);
}
#[test]
fn fetch_mut_aspects() {
assert_eq!(Write::<Res>::reads(), vec![]);
assert_eq!(Write::<Res>::writes(), vec![ResourceId::new::<Res>()]);
let mut res = Resources::new();
res.insert(Res);
<Write<Res> as SystemData>::fetch(&res);
}
#[test]
fn add() {
struct Foo;
let mut res = Resources::new();
res.insert(Res);
assert!(res.has_value::<Res>());
assert!(!res.has_value::<Foo>());
}
#[allow(unused)]
#[test]
#[should_panic(expected = "Already borrowed")]
fn read_write_fails() {
let mut res = Resources::new();
res.insert(Res);
let read: Fetch<Res> = res.fetch();
let write: FetchMut<Res> = res.fetch_mut();
}
#[allow(unused)]
#[test]
#[should_panic(expected = "Already borrowed mutably")]
fn write_read_fails() {
let mut res = Resources::new();
res.insert(Res);
let write: FetchMut<Res> = res.fetch_mut();
let read: Fetch<Res> = res.fetch();
}
#[test]
fn default_works() {
struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = Write<'a, i32>;
fn run(&mut self, mut data: Self::SystemData) {
assert_eq!(*data, 0);
*data = 33;
}
}
let mut res = Resources::new();
assert!(res.try_fetch::<i32>().is_none());
let mut sys = Sys;
RunNow::setup(&mut sys, &mut res);
sys.run_now(&res);
assert!(res.try_fetch::<i32>().is_some());
assert_eq!(*res.fetch::<i32>(), 33);
}
}