extern crate shred;
use ahash::AHashMap as HashMap;
use shred::{
cell::{AtomicRef, AtomicRefMut},
Accessor, AccessorCow, CastFrom, DispatcherBuilder, DynamicSystemData, MetaTable, Read,
Resource, ResourceId, System, SystemData, World,
};
struct Dependencies {
reads: Vec<ResourceId>,
writes: Vec<ResourceId>,
}
impl Accessor for Dependencies {
fn try_new() -> Option<Self> {
None
}
fn reads(&self) -> Vec<ResourceId> {
let mut reads = self.reads.clone();
reads.push(ResourceId::new::<ReflectionTable>());
reads
}
fn writes(&self) -> Vec<ResourceId> {
self.writes.clone()
}
}
struct DynamicSystem {
dependencies: Dependencies,
script: fn(ScriptInput),
}
impl<'a> System<'a> for DynamicSystem {
type SystemData = ScriptSystemData<'a>;
fn run(&mut self, mut data: Self::SystemData) {
let meta = data.meta_table;
let reads: Vec<&dyn Reflection> = data
.reads
.iter()
.map(|resource| meta.get(&**resource).expect("Not registered in meta table"))
.collect();
let writes: Vec<&mut dyn Reflection> = data
.writes
.iter_mut()
.map(|resource| {
let res: &mut dyn Reflection = meta.get_mut(&mut **resource).expect(
"Not registered in meta \
table",
);
res
})
.collect();
let input = ScriptInput { reads, writes };
(self.script)(input);
}
fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> {
AccessorCow::Ref(&self.dependencies)
}
fn setup(&mut self, _res: &mut World) {
}
}
trait Reflection {
fn call_method(&self, s: &str);
}
unsafe impl<T> CastFrom<T> for dyn Reflection
where
T: Reflection + 'static,
{
fn cast(t: *mut T) -> *mut Self {
t
}
}
type ReflectionTable = MetaTable<dyn Reflection>;
struct ResourceTable {
map: HashMap<String, ResourceId>,
}
impl ResourceTable {
fn new() -> Self {
ResourceTable {
map: HashMap::default(),
}
}
fn register<T: Resource>(&mut self, name: &str) {
self.map.insert(name.to_owned(), ResourceId::new::<T>());
}
fn get(&self, name: &str) -> ResourceId {
self.map.get(name).cloned().unwrap()
}
}
struct ScriptInput<'a> {
reads: Vec<&'a dyn Reflection>,
writes: Vec<&'a mut dyn Reflection>,
}
struct ScriptSystemData<'a> {
meta_table: Read<'a, ReflectionTable>,
reads: Vec<AtomicRef<'a, dyn Resource + 'static>>,
writes: Vec<AtomicRefMut<'a, dyn Resource + 'static>>,
}
impl<'a> DynamicSystemData<'a> for ScriptSystemData<'a> {
type Accessor = Dependencies;
fn setup(_accessor: &Dependencies, _res: &mut World) {}
fn fetch(access: &Dependencies, world: &'a World) -> Self {
let reads = access
.reads
.iter()
.map(|id| {
let id = id.clone();
let res = unsafe { world.try_fetch_internal(id) };
AtomicRef::map(
res.expect("bug: the requested resource does not exist")
.borrow(),
Box::as_ref,
)
})
.collect();
let writes = access
.writes
.iter()
.map(|id| {
let id = id.clone();
let res = unsafe { world.try_fetch_internal(id) };
AtomicRefMut::map(
res.expect("bug: the requested resource does not exist")
.borrow_mut(),
Box::as_mut,
)
})
.collect();
ScriptSystemData {
meta_table: SystemData::fetch(world),
reads,
writes,
}
}
}
fn create_script_sys(res: &World) -> DynamicSystem {
fn script(input: ScriptInput) {
input.reads[0].call_method("bar");
input.writes[0].call_method("foo");
}
let reads = vec!["Bar"];
let writes = vec!["Foo"];
let table = res.fetch::<ResourceTable>();
DynamicSystem {
dependencies: Dependencies {
reads: reads.iter().map(|r| table.get(r)).collect(),
writes: writes.iter().map(|r| table.get(r)).collect(),
},
script,
}
}
fn main() {
#[derive(Debug, Default)]
struct Foo;
impl Reflection for Foo {
fn call_method(&self, s: &str) {
match s {
"foo" => println!("Hello from Foo"),
"bar" => println!("You gotta ask somebody else"),
_ => panic!("The error handling of this example is non-ideal"),
}
}
}
#[derive(Debug, Default)]
struct Bar;
impl Reflection for Bar {
fn call_method(&self, s: &str) {
match s {
"bar" => println!("Hello from Bar"),
"foo" => println!("You gotta ask somebody else"),
_ => panic!("The error handling of this example is non-ideal"),
}
}
}
struct NormalSys;
impl<'a> System<'a> for NormalSys {
type SystemData = (Read<'a, Foo>, Read<'a, Bar>);
fn run(&mut self, (foo, bar): Self::SystemData) {
println!("Fetched foo: {:?}", &foo as &Foo);
println!("Fetched bar: {:?}", &bar as &Bar);
}
}
let mut res = World::empty();
{
let mut table = res.entry().or_insert_with(ReflectionTable::new);
table.register::<Foo>();
table.register::<Bar>();
}
{
let mut table = res.entry().or_insert_with(ResourceTable::new);
table.register::<Foo>("Foo");
table.register::<Bar>("Bar");
}
let mut dispatcher = DispatcherBuilder::new()
.with(NormalSys, "normal", &[])
.build();
dispatcher.setup(&mut res);
let script0 = create_script_sys(&res);
let mut scripts = DispatcherBuilder::new()
.with(script0, "script0", &[])
.build();
scripts.setup(&mut res);
loop {
dispatcher.dispatch(&res);
scripts.dispatch(&res);
}
}