Skip to content

Commit

Permalink
save work
Browse files Browse the repository at this point in the history
  • Loading branch information
iiYese committed Nov 8, 2023
1 parent 937f6bf commit 64796c3
Showing 1 changed file with 140 additions and 37 deletions.
177 changes: 140 additions & 37 deletions src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,80 @@ use bevy::ecs::{
use std::marker::PhantomData;

/// Builder API to construct hierarchies of relations.
/// ```
/// world.spawn(bundle).scope::<ChildOf>(|scope| {
/// // x, y, z are implicitly `ChildOf` the last spawned entity
/// scope.add(x)
/// .add(y)
/// .add(z)
/// .scope::<ChildOf>(|scope| {
/// // a, b are implicitly `ChildOf` the last spawned entity (z)
/// scope.add(a)
/// .add(b);
/// });
/// });
/// ```
pub struct Scope<API, E> {
top: Entity,
last: Entity,
api: API,
_phantom: PhantomData<E>,
}

/// Ext trait to produce a [`Scope`] from an [`EntityWorldMut`].
pub trait AeryEntityWorldMutExt<'a> {
#[allow(missing_docs)]
fn scope<R: Relation>(&mut self, func: impl FnMut(&mut Scope<&'_ mut World, R>)) -> &mut Self;
}

impl<'a> AeryEntityWorldMutExt<'a> for EntityWorldMut<'a> {
fn scope<R: Relation>(
&mut self,
mut func: impl FnMut(&mut Scope<&'_ mut World, R>),
) -> &mut Self {
let _ = R::ZST_OR_PANIC;

let id = self.id();

self.world_scope(|world| {
let mut scope = Scope {
top: id,
last: id,
api: world,
_phantom: PhantomData,
};

func(&mut scope);
});

self
}
}

impl<T: Relation> Scope<&'_ mut World, T> {
/// Scope the last spawned entity via `R`. Any targets or hosts that are added in the scope
/// implicitly use `R` as the edge.
pub fn scope<R: Relation>(
&mut self,
mut func: impl FnMut(&mut Scope<&'_ mut World, R>),
) -> &mut Self {
let _ = R::ZST_OR_PANIC;

let mut inner = Scope::<&'_ mut World, R> {
top: self.last,
last: self.last,
api: self.api,
_phantom: PhantomData,
};

func(&mut inner);

self
}
}

impl<R: Relation> Scope<&'_ mut World, R> {
/// Spawn an entity from a bundle and have it target the currently scoped entity via.
/// Spawn an entity from a bundle and have it target the currently scoped entity via `R`.
pub fn add(&mut self, bundle: impl Bundle) -> &mut Self {
let id = self.api.spawn(bundle).id();
Command::apply(Set::<R>::new(id, self.top), self.api);
Expand Down Expand Up @@ -69,16 +134,47 @@ impl<R: Relation> Scope<&'_ mut World, R> {
}
}

impl<T: Relation> Scope<&'_ mut World, T> {
/// Ext trait to produce a [`Scope`] from an [`EntityCommands`].
pub trait AeryEntityCommandsExt<'w, 's, 'a> {
#[allow(missing_docs)]
fn scope<R: Relation>(
&mut self,
func: impl FnMut(&mut Scope<&'_ mut Commands, R>),
) -> &mut Self;
}

impl<'w, 's, 'a> AeryEntityCommandsExt<'w, 's, 'a> for EntityCommands<'w, 's, 'a> {
fn scope<R: Relation>(
&mut self,
mut func: impl FnMut(&mut Scope<&'_ mut Commands, R>),
) -> &mut Self {
let _ = R::ZST_OR_PANIC;

let id = self.id();

let mut scope = Scope {
top: id,
last: id,
api: self.commands(),
_phantom: PhantomData,
};

func(&mut scope);

self
}
}

impl<T: Relation> Scope<&'_ mut Commands<'_, '_>, T> {
/// Scope the last spawned entity via `R`. Any targets or hosts that are added in the scope
/// implicitly use `R` as the edge.
pub fn scope<R: Relation>(
&mut self,
mut func: impl for<'i> FnMut(&mut Scope<&'_ mut World, R>),
mut func: impl FnMut(&mut Scope<&'_ mut Commands<'_, '_>, R>),
) -> &mut Self {
let _ = R::ZST_OR_PANIC;

let mut inner = Scope::<&'_ mut World, R> {
let mut inner = Scope::<&'_ mut Commands<'_, '_>, R> {
top: self.last,
last: self.last,
api: self.api,
Expand All @@ -91,44 +187,51 @@ impl<T: Relation> Scope<&'_ mut World, T> {
}
}

/// Ext trait to produce a [`Scope`] from an [`EntityWorldMut`].
pub trait AeryEntityWorldMutExt<'a> {
#[allow(missing_docs)]
fn scope<R: Relation>(
&mut self,
func: impl for<'i> FnMut(&mut Scope<&'_ mut World, R>),
) -> &mut Self;
}

impl<'a> AeryEntityWorldMutExt<'a> for EntityWorldMut<'a> {
fn scope<R: Relation>(
&mut self,
mut func: impl for<'i> FnMut(&mut Scope<&'_ mut World, R>),
) -> &mut Self {
let _ = R::ZST_OR_PANIC;

let id = self.id();
impl<R: Relation> Scope<&'_ mut Commands<'_, '_>, R> {
/// Spawn an entity from a bundle and have it target the currently scoped entity via `R`.
pub fn add(&mut self, bundle: impl Bundle) -> &mut Self {
let id = self.api.spawn(bundle).id();
self.api.add(Set::<R>::new(id, self.top));
self.last = id;
self
}

self.world_scope(|world| {
let mut scope = Scope {
top: id,
last: id,
api: world,
_phantom: PhantomData,
};
/// Spawn an entity from a bundle and set it as a target of the currently scoped entity.
pub fn add_target(&mut self, bundle: impl Bundle) -> &mut Self {
let id = self.api.spawn(bundle).id();
Command::apply(Set::<R>::new(self.top, id), self.api);
self.last = id;
self
}

func(&mut scope);
});
/// Spawn an entity and have it target the currently scoped entity via.
/// This function takes a closure to provide entity mut access.
pub fn add_and(&mut self, mut func: impl for<'e> FnMut(&mut EntityWorldMut<'e>)) -> &mut Self {
let id = {
let mut spawned = self.api.spawn(());
func(&mut spawned);
spawned.id()
};

Command::apply(Set::<R>::new(id, self.top), self.api);
self.last = id;
self
}
}

/// Ext trait to produce a [`Scope`] from an [`EntityCommands`].
pub trait AeryEntityCommandsExt<'a> {
#[allow(missing_docs)]
fn scope<R: Relation>(
/// Spawn an entity and set it as a target of the currently scoped entity.
/// This function takes a closure to provide entity mut access.
pub fn add_target_and(
&mut self,
func: impl for<'i> FnMut(&mut Scope<&'_ mut Commands, R>),
) -> &mut Self;
mut func: impl for<'e> FnMut(&mut EntityWorldMut<'e>),
) -> &mut Self {
let id = {
let mut spawned = self.api.spawn(());
func(&mut spawned);
spawned.id()
};

Command::apply(Set::<R>::new(self.top, id), self.api);
self.last = id;
self
}
}

0 comments on commit 64796c3

Please sign in to comment.