Files
orchid/orchid-extension/src/system_ctor.rs
Lawrence Bethlenfalvy 0909524dee
Some checks failed
Rust / build (push) Failing after 3m52s
Compiles again after command subsystem
terrified to start testing
2026-03-27 23:50:58 +01:00

154 lines
4.8 KiB
Rust

use std::any::Any;
use std::fmt::Debug;
use std::rc::Rc;
use orchid_base::{BoxedIter, box_empty, box_once};
use ordered_float::NotNan;
use crate::{DynSystem, DynSystemHandle, System, SystemCard, SystemHandle, api};
#[derive(Debug)]
pub struct Cted<Ctor: SystemCtor + ?Sized> {
pub deps: <Ctor::Deps as DepDef>::Sat,
pub inst: Rc<Ctor::Instance>,
}
impl<C: SystemCtor + ?Sized> Clone for Cted<C> {
fn clone(&self) -> Self { Self { deps: self.deps.clone(), inst: self.inst.clone() } }
}
pub trait DynCted: Debug + 'static {
fn as_any(self: Rc<Self>) -> Rc<dyn Any>;
fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>;
fn inst(&self) -> Rc<dyn DynSystem>;
}
impl<C: SystemCtor + ?Sized> DynCted for Cted<C> {
fn as_any(self: Rc<Self>) -> Rc<dyn Any> { self }
fn deps<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { self.deps.iter() }
fn inst(&self) -> Rc<dyn DynSystem> { self.inst.clone() }
}
pub type CtedObj = Rc<dyn DynCted>;
pub trait DepSat: Debug + Clone + 'static {
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)>;
}
pub trait DepDef: Debug {
type Sat: DepSat;
fn report(names: &mut impl FnMut(&'static str));
fn create(take: &mut impl FnMut() -> api::SysId) -> Self::Sat;
}
impl<T: SystemCard> DepSat for SystemHandle<T> {
fn iter<'a>(&'a self) -> BoxedIter<'a, &'a (dyn DynSystemHandle + 'a)> { box_once(self) }
}
impl<T: SystemCard> DepDef for T {
type Sat = SystemHandle<Self>;
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: Debug + 'static {
type Deps: DepDef;
type Instance: System<Ctor = Self>;
type Card: SystemCard<Ctor = Self>;
const NAME: &'static str;
const VERSION: f64;
/// Create a system instance.
fn inst(&self, deps: <Self::Deps as DepDef>::Sat) -> Self::Instance;
}
pub trait DynSystemCtor: Debug + 'static {
fn decl(&self, id: api::SysDeclId) -> api::SystemDecl;
fn new_system(&self, new: &api::NewSystem) -> CtedObj;
}
impl<T: SystemCtor> 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 deps = T::Deps::create(&mut || ids.next().unwrap());
let inst = Rc::new(self.inst(deps.clone()));
Rc::new(Cted::<T> { deps, inst })
}
}
mod dep_set_tuple_impls {
use orchid_base::{BoxedIter, box_chain};
use pastey::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
}