use super::entity::Entity;
use super::world::World;
pub trait IntoBundle {
fn spawn_into(self, world: &mut World, entity: Entity);
}
pub trait Component: 'static {}
impl<C: Component> IntoBundle for C {
fn spawn_into(self, world: &mut World, entity: Entity) {
world.insert(entity, self);
}
}
macro_rules! impl_bundle_for_tuple {
($($name:ident),+) => {
impl<$($name: IntoBundle),+> IntoBundle for ($($name,)+) {
fn spawn_into(self, world: &mut World, entity: Entity) {
#[allow(non_snake_case)]
let ($($name,)+) = self;
$($name.spawn_into(world, entity);)+
}
}
};
}
impl_bundle_for_tuple!(A);
impl_bundle_for_tuple!(A, B);
impl_bundle_for_tuple!(A, B, C);
impl_bundle_for_tuple!(A, B, C, D);
impl_bundle_for_tuple!(A, B, C, D, E);
impl_bundle_for_tuple!(A, B, C, D, E, F);
impl_bundle_for_tuple!(A, B, C, D, E, F, G);
impl_bundle_for_tuple!(A, B, C, D, E, F, G, H);
impl World {
pub fn spawn<B: IntoBundle>(&mut self, bundle: B) -> Entity {
let entity = self.spawn_empty();
self.insert(entity, crate::widget::Widget);
bundle.spawn_into(self, entity);
entity
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Foo(u32);
struct Bar;
impl Component for Foo {}
impl Component for Bar {}
struct FooBuilder {
foo: Foo,
bar: Option<Bar>,
}
impl IntoBundle for FooBuilder {
fn spawn_into(self, world: &mut World, entity: Entity) {
world.insert(entity, self.foo);
if let Some(bar) = self.bar {
world.insert(entity, bar);
}
}
}
#[test]
fn spawn_single_component() {
let mut world = World::default();
let e = world.spawn(Foo(7));
assert_eq!(world.get::<Foo>(e).unwrap().0, 7);
}
#[test]
fn spawn_tuple_of_components() {
let mut world = World::default();
let e = world.spawn((Foo(3), Bar));
assert_eq!(world.get::<Foo>(e).unwrap().0, 3);
assert!(world.has::<Bar>(e));
}
#[test]
fn spawn_tuple_mixing_builder_and_component() {
let mut world = World::default();
let e = world.spawn((
FooBuilder {
foo: Foo(9),
bar: Some(Bar),
},
Foo(11),
));
assert_eq!(world.get::<Foo>(e).unwrap().0, 11);
assert!(world.has::<Bar>(e));
}
#[test]
fn spawn_unfolds_components() {
let mut world = World::default();
let e = world.spawn(FooBuilder {
foo: Foo(42),
bar: Some(Bar),
});
assert_eq!(world.get::<Foo>(e).unwrap().0, 42);
assert!(world.has::<Bar>(e));
}
#[test]
fn optional_satellite_absent() {
let mut world = World::default();
let e = world.spawn(FooBuilder {
foo: Foo(1),
bar: None,
});
assert!(world.has::<Foo>(e));
assert!(!world.has::<Bar>(e));
}
}