use alloc::{boxed::Box, vec::Vec};
use core::marker::PhantomData;
use crate::{
bundle::Bundle,
event::Event,
schedule::{BoxedCondition, SystemCondition},
system::{IntoObserverSystem, IntoSystem},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
pub(crate) struct ObserverCondition {
condition: BoxedCondition,
}
impl ObserverCondition {
pub(crate) fn new<M>(condition: impl SystemCondition<M>) -> Self {
Self {
condition: Box::new(IntoSystem::into_system(condition)),
}
}
pub(crate) fn from_boxed(condition: BoxedCondition) -> Self {
Self { condition }
}
pub(crate) fn initialize(&mut self, world: &mut World) {
self.condition.initialize(world);
}
pub(crate) unsafe fn check(&mut self, world: UnsafeWorldCell) -> bool {
unsafe { self.condition.run_unsafe((), world) }.unwrap_or(false)
}
}
#[doc(hidden)]
pub struct ObserverWithConditionMarker;
pub struct ObserverWithCondition<E: Event, B: Bundle, M, S: IntoObserverSystem<E, B, M>> {
pub(crate) system: S,
pub(crate) conditions: Vec<BoxedCondition>,
pub(crate) _marker: PhantomData<fn() -> (E, B, M)>,
}
impl<E: Event, B: Bundle, M, S: IntoObserverSystem<E, B, M>> ObserverWithCondition<E, B, M, S> {
pub fn run_if<C, CM>(mut self, condition: C) -> Self
where
C: SystemCondition<CM>,
{
self.conditions
.push(Box::new(IntoSystem::into_system(condition)));
self
}
pub(crate) fn take_conditions(self) -> (S, Vec<ObserverCondition>) {
let conditions = self
.conditions
.into_iter()
.map(ObserverCondition::from_boxed)
.collect();
(self.system, conditions)
}
}