use crate::{
bundle::{Bundle, InsertMode, NoBundleEffect},
change_detection::MaybeLocation,
entity::Entity,
error::Result,
event::Event,
message::{Message, Messages},
resource::Resource,
schedule::ScheduleLabel,
system::{IntoSystem, SystemId, SystemInput},
world::{FromWorld, SpawnBatchIter, World},
};
pub trait Command<Out = ()>: Send + 'static {
fn apply(self, world: &mut World) -> Out;
}
impl<F, Out> Command<Out> for F
where
F: FnOnce(&mut World) -> Out + Send + 'static,
{
fn apply(self, world: &mut World) -> Out {
self(world)
}
}
#[track_caller]
pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
where
I: IntoIterator + Send + Sync + 'static,
I::Item: Bundle<Effect: NoBundleEffect>,
{
let caller = MaybeLocation::caller();
move |world: &mut World| {
SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);
}
}
#[track_caller]
pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>
where
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
B: Bundle<Effect: NoBundleEffect>,
{
let caller = MaybeLocation::caller();
move |world: &mut World| -> Result {
world.try_insert_batch_with_caller(batch, insert_mode, caller)?;
Ok(())
}
}
#[track_caller]
pub fn init_resource<R: Resource + FromWorld>() -> impl Command {
move |world: &mut World| {
world.init_resource::<R>();
}
}
#[track_caller]
pub fn insert_resource<R: Resource>(resource: R) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
world.insert_resource_with_caller(resource, caller);
}
}
pub fn remove_resource<R: Resource>() -> impl Command {
move |world: &mut World| {
world.remove_resource::<R>();
}
}
pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command<Result> {
move |world: &mut World| -> Result {
world.run_system(id)?;
Ok(())
}
}
pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command<Result>
where
I: SystemInput<Inner<'static>: Send> + 'static,
{
move |world: &mut World| -> Result {
world.run_system_with(id, input)?;
Ok(())
}
}
pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>
where
M: 'static,
S: IntoSystem<(), (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached(system)?;
Ok(())
}
}
pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>
where
I: SystemInput<Inner<'static>: Send> + Send + 'static,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached_with(system, input)?;
Ok(())
}
}
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>
where
I: SystemInput + Send + 'static,
O: Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system(system_id)?;
Ok(())
}
}
pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command<Result>
where
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system_cached(system)?;
Ok(())
}
}
pub fn run_schedule(label: impl ScheduleLabel) -> impl Command<Result> {
move |world: &mut World| -> Result {
world.try_run_schedule(label)?;
Ok(())
}
}
#[track_caller]
pub fn trigger<'a, E: Event<Trigger<'a>: Default>>(mut event: E) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
world.trigger_ref_with_caller(
&mut event,
&mut <E::Trigger<'_> as Default>::default(),
caller,
);
}
}
#[track_caller]
pub fn trigger_with<E: Event<Trigger<'static>: Send + Sync>>(
mut event: E,
mut trigger: E::Trigger<'static>,
) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
world.trigger_ref_with_caller(&mut event, &mut trigger, caller);
}
}
#[track_caller]
pub fn write_message<M: Message>(message: M) -> impl Command {
let caller = MaybeLocation::caller();
move |world: &mut World| {
let mut messages = world.resource_mut::<Messages<M>>();
messages.write_with_caller(message, caller);
}
}