use std::{any::TypeId, hash::Hash};
use bevy_utils::{define_label, intern::Interned};
use crate::system::{BoxedSystem, IntoSystem};
pub use bevy_utils::label::{DynEq, DynHash};
pub use pi_world_macros::{ScheduleLabel, StageLabel, SystemSet};
define_label!(
SystemSet,
SYSTEM_SET_INTERNER
);
define_label!(
StageLabel,
STAGE_LABEL_INTERNER
);
define_label!(
ScheduleLabel,
SCHEDULE_LABEL_INTERNER
);
pub trait IntoNodeType<Marker>
where
Self: Sized,
{
fn into_node_type(self) -> NodeType;
}
pub trait IntoSystemSetConfigs
where
Self: Sized,
{
fn into_configs(self) -> SetConfig;
fn in_set(self, set: impl SystemSet) -> SetConfig {
self.into_configs().in_set(set)
}
fn in_schedule(self, schedule: impl ScheduleLabel) -> SetConfig {
self.into_configs().in_schedule(schedule)
}
fn before<M>(self, after: impl IntoNodeType<M>) -> SetConfig {
self.into_configs().before(after)
}
fn after<M>(self, before: impl IntoNodeType<M>) -> SetConfig {
self.into_configs().after(before)
}
fn run_if<M>(self, condition: impl Condition<M>) -> SetConfig {
self.into_configs().run_if(condition)
}
}
pub struct SetConfig {
pub set: Interned<dyn SystemSet>,
pub(crate) config: BaseConfig,
}
impl IntoSystemSetConfigs for SetConfig {
fn into_configs(self) -> SetConfig {
self
}
fn in_set(mut self, set: impl SystemSet) -> SetConfig {
self.config.sets.push(set.intern());
self
}
fn in_schedule(mut self, schedule: impl ScheduleLabel) -> SetConfig {
self.config.schedules.push(schedule.intern());
self
}
fn before<M>(mut self, after: impl IntoNodeType<M>) -> SetConfig {
self.config.before.push(after.into_node_type());
self
}
fn after<M>(mut self, before: impl IntoNodeType<M>) -> SetConfig {
self.config.after.push(before.into_node_type());
self
}
fn run_if<M>(mut self, condition: impl Condition<M>) -> SetConfig {
self.config.conditions.push(BoxedSystem::Sync(Box::new(IntoSystem::<M, bool>::into_system(condition))));
self
}
}
impl<T: SystemSet> IntoNodeType<()> for T {
fn into_node_type(self) -> NodeType {
NodeType::Set(self.intern())
}
}
impl<T: SystemSet> IntoSystemSetConfigs for T {
fn into_configs(self) -> SetConfig {
SetConfig{
set: self.intern(),
config: BaseConfig {
sets: Vec::with_capacity(256),
schedules: Vec::with_capacity(256),
before: Vec::with_capacity(256),
after: Vec::with_capacity(256),
conditions: Vec::with_capacity(256),
},
}
}
}
pub trait IntoSystemConfigs<Marker>
where
Self: Sized,
{
fn into_configs(self) -> SystemConfig;
fn in_set(self, set: impl SystemSet) -> SystemConfig {
self.into_configs().in_set(set)
}
fn in_schedule(self, schedule: impl ScheduleLabel) -> SystemConfig {
self.into_configs().in_schedule(schedule)
}
fn before<M>(self, after: impl IntoNodeType<M>) -> SystemConfig {
self.into_configs().before(after)
}
fn after<M>(self, before: impl IntoNodeType<M>) -> SystemConfig {
self.into_configs().after(before)
}
fn run_if<M>(self, condition: impl Condition<M>) -> SystemConfig {
self.into_configs().run_if(condition)
}
}
pub trait Condition<Marker>: IntoSystem<Marker, bool>
where
Self: Sized,
{
}
pub struct SystemConfig {
pub(crate) system: BoxedSystem<()>,
pub(crate) config: BaseConfig,
}
impl IntoSystemConfigs<()> for SystemConfig {
#[inline]
fn into_configs(self) -> SystemConfig {
self
}
fn in_set(mut self, set: impl SystemSet) -> SystemConfig {
self.config.sets.push(set.intern());
self
}
fn in_schedule(mut self, schedule: impl ScheduleLabel) -> SystemConfig {
self.config.schedules.push(schedule.intern());
self
}
fn before<M>(mut self, after: impl IntoNodeType<M>) -> SystemConfig {
self.config.before.push(after.into_node_type());
self
}
fn after<M>(mut self, before: impl IntoNodeType<M>) -> SystemConfig {
self.config.after.push(before.into_node_type());
self
}
fn run_if<M>(mut self, condition: impl Condition<M>) -> SystemConfig {
self.config.conditions.push(BoxedSystem::Sync(Box::new(IntoSystem::<M, bool>::into_system(condition))));
self
}
}
impl<Marker, T: IntoSystem<Marker, ()>> IntoSystemConfigs<Marker> for T {
fn into_configs(self) -> SystemConfig {
SystemConfig {
system: BoxedSystem::Sync(Box::new(self.into_system())),
config: BaseConfig {
sets: Vec::with_capacity(256),
schedules: Vec::with_capacity(256),
before: Vec::with_capacity(256),
after: Vec::with_capacity(256),
conditions: Vec::with_capacity(256),
},
}
}
}
impl<Marker, T: IntoSystem<Marker, bool>> Condition<Marker> for T {}
impl<Marker, T: IntoSystem<Marker, ()> + 'static> IntoNodeType<(usize, Marker)> for T {
fn into_node_type(self) -> NodeType {
NodeType::System(TypeId::of::<Self>())
}
}
#[derive(Default)]
pub struct BaseConfig {
pub(crate) sets: Vec<Interned<dyn SystemSet>>,
pub(crate) schedules: Vec<Interned<dyn ScheduleLabel>>, pub(crate) before: Vec<NodeType>, pub(crate) after: Vec<NodeType>, pub(crate) conditions: Vec<BoxedSystem<bool>>,
}
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum NodeType {
Set(Interned<dyn SystemSet>),
System(std::any::TypeId),
}