use std::any::Any; use std::sync::Arc; use orchid_base::boxed_iter::{BoxedIter, box_empty, box_once}; use ordered_float::NotNan; use crate::api; use crate::other_system::{DynSystemHandle, SystemHandle}; use crate::system::{DynSystem, System, SystemCard}; pub struct Cted { pub deps: ::Sat, pub inst: Arc, } impl Clone for Cted { fn clone(&self) -> Self { Self { deps: self.deps.clone(), inst: self.inst.clone() } } } pub trait DynCted: Send + Sync + 'static { fn as_any(&self) -> &dyn Any; fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>; fn inst(&self) -> Arc; } impl DynCted for Cted { fn as_any(&self) -> &dyn Any { self } fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { self.deps.iter() } fn inst(&self) -> Arc { self.inst.clone() } } pub type CtedObj = Arc; pub trait DepSat: Clone + Send + Sync + 'static { fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>; } pub trait DepDef { type Sat: DepSat; fn report(names: &mut impl FnMut(&'static str)); fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat; } impl DepSat for SystemHandle { fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_once(self) } } impl DepDef for T { type Sat = SystemHandle; fn report(names: &mut impl FnMut(&'static str)) { names(T::Ctor::NAME) } fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat { SystemHandle::new(take()) } } impl DepSat for () { fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_empty() } } impl DepDef for () { type Sat = (); fn create(_: &mut impl FnMut() -> api::SysId) -> Self::Sat {} fn report(_: &mut impl FnMut(&'static str)) {} } pub trait SystemCtor: Send + Sync + 'static { type Deps: DepDef; type Instance: System; const NAME: &'static str; const VERSION: f64; fn inst() -> Option; } pub trait DynSystemCtor: Send + Sync + 'static { fn decl(&self, id: api::SysDeclId) -> api::SystemDecl; fn new_system(&self, new: &api::NewSystem) -> CtedObj; } impl DynSystemCtor for T { fn decl(&self, id: api::SysDeclId) -> api::SystemDecl { // Version is equivalent to priority for all practical purposes let priority = NotNan::new(T::VERSION).unwrap(); // aggregate depends names let mut depends = Vec::new(); T::Deps::report(&mut |n| depends.push(n.to_string())); api::SystemDecl { name: T::NAME.to_string(), depends, id, priority } } fn new_system(&self, api::NewSystem { system: _, id: _, depends }: &api::NewSystem) -> CtedObj { let mut ids = depends.iter().copied(); let inst = Arc::new(T::inst().expect("Constructor did not create system")); let deps = T::Deps::create(&mut || ids.next().unwrap()); Arc::new(Cted:: { deps, inst }) } } mod dep_set_tuple_impls { use orchid_base::box_chain; use orchid_base::boxed_iter::BoxedIter; use paste::paste; use super::{DepDef, DepSat}; use crate::api; use crate::system_ctor::DynSystemHandle; macro_rules! dep_set_tuple_impl { ($($name:ident),*) => { impl<$( $name :DepSat ),*> DepSat for ( $( $name , )* ) { fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { // we're using the Paste crate to convert the names to lowercase, // so `dep_set_tuple_impl!(A, B, C)` generates `let (a, b, c,) = self;` // This step isn't really required for correctness, but Rust warns about uppercase // variable names. paste!{ let ( $( [< $name :lower >] , )* ) = self; box_chain! ( $( [< $name :lower >] .iter() ),* ) } } } impl<$( $name :DepDef ),*> DepDef for ( $( $name , )* ) { type Sat = ( $( $name ::Sat , )* ); fn report(names: &mut impl FnMut(&'static str)) { $( $name ::report(names); )* } fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat { ( $( $name ::create(take), )* ) } } }; } dep_set_tuple_impl!(A); dep_set_tuple_impl!(A, B); // 2 dep_set_tuple_impl!(A, B, C); dep_set_tuple_impl!(A, B, C, D); // 4 dep_set_tuple_impl!(A, B, C, D, E); dep_set_tuple_impl!(A, B, C, D, E, F); dep_set_tuple_impl!(A, B, C, D, E, F, G); dep_set_tuple_impl!(A, B, C, D, E, F, G, H); // 8 dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I); dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J); dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K); dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L); // 12 dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M); dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); dep_set_tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); // 16 }