use flax::{
component,
components::{child_of, name},
entity_ids,
metadata::debuggable,
relations_like, Debuggable, Entity, EntityBuilder, FetchExt, Query, World,
};
use itertools::Itertools;
#[derive(Debug, Clone)]
pub struct Countdown<const C: usize>(usize);
impl<const C: usize> Countdown<C> {
pub fn new() -> Self {
Self(0)
}
pub fn proceed(&mut self) -> bool {
self.0 += 1;
match self.0.cmp(&C) {
std::cmp::Ordering::Less => false,
std::cmp::Ordering::Equal => true,
std::cmp::Ordering::Greater => {
eprintln!("Sire!");
self.0 = C;
true
}
}
}
}
impl<const C: usize> Default for Countdown<C> {
fn default() -> Self {
Self::new()
}
}
#[test]
fn visitors() {
use flax::Debuggable;
component! {
health: f32 => [Debuggable],
count: Countdown<3> => [Debuggable],
}
let mut world = World::new();
EntityBuilder::new()
.set(name(), "Holy Hand Grenade of Antioch".to_string())
.spawn(&mut world);
let mut builder = EntityBuilder::new();
for i in 0..128 {
let perm = ((i as f32 + 0.4) * (i as f32) * 6.0) % 100.0;
builder
.set(name(), format!("Clone#{i}"))
.set(health(), perm)
.spawn(&mut world);
}
eprintln!("World: {world:#?}");
}
#[test]
fn relations() {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
enum RelationKind {
Mom,
Dad,
}
component! {
hobby: &'static str => [ Debuggable ],
profession: &'static str => [ Debuggable ],
child_of(e): RelationKind => [ Debuggable ],
}
let mut world = World::new();
let parent = EntityBuilder::new()
.set(name(), "Jessica".to_string())
.set(hobby(), "Reading")
.spawn(&mut world);
let parent2 = EntityBuilder::new()
.set(name(), "Jack".to_string())
.set(hobby(), "Crocheting")
.spawn(&mut world);
let child = EntityBuilder::new()
.set(name(), "John".to_string())
.set(hobby(), "Studying")
.set(child_of(parent), RelationKind::Mom)
.spawn(&mut world);
let child2 = EntityBuilder::new()
.set(name(), "Sally".to_string())
.set(hobby(), "Hockey")
.set(child_of(parent), RelationKind::Mom)
.set(profession(), "Student")
.spawn(&mut world);
assert!(world.get(child_of(parent).id(), debuggable()).is_ok());
let child3 = EntityBuilder::new()
.set(name(), "Reacher".to_string())
.set(hobby(), "Hockey")
.set(child_of(parent2), RelationKind::Dad)
.spawn(&mut world);
let mut query = Query::new((name(), child_of(parent)));
assert!(world.get(child_of(parent).id(), debuggable()).is_ok());
assert!(world.get(child_of(parent2).id(), debuggable()).is_ok());
let items = query
.borrow(&world)
.iter()
.map(|(a, b)| (a.clone(), *b))
.sorted()
.collect_vec();
assert_eq!(
items,
[
("John".to_string(), RelationKind::Mom),
("Sally".to_string(), RelationKind::Mom)
]
);
eprintln!("World: {world:#?}");
let mut query = Query::new((name(), relations_like(child_of)));
let mut query = query.borrow(&world);
let items = query
.iter()
.map(|(name, relations)| (name, relations.collect_vec()))
.sorted()
.collect_vec();
assert_eq!(
items,
[
(&"Jack".to_string(), vec![]),
(&"Jessica".to_string(), vec![]),
(&"John".to_string(), vec![(parent, &RelationKind::Mom)]),
(&"Reacher".to_string(), vec![(parent2, &RelationKind::Dad)]),
(&"Sally".to_string(), vec![(parent, &RelationKind::Mom)])
]
);
drop(query);
eprintln!("Detaching parent: {parent}");
world.detach(parent);
assert!(world.get(child, child_of(parent)).is_err());
assert!(world.get(child2, child_of(parent)).is_err());
assert!(world.get(child3, child_of(parent2)).is_ok());
eprintln!("Before: {world:#?}");
world.clear(parent2).unwrap();
world.detach(parent2);
eprintln!("After: {world:#?}");
assert!(world.is_alive(parent2));
assert!(world.get(parent2, name()).is_err());
assert!(world.get(child3, child_of(parent2)).is_err());
}
#[test]
fn build_hierarchy() {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
enum RelationKind {
Dad,
}
component! {
hobby: &'static str => [ Debuggable ],
profession: &'static str => [ Debuggable ],
child_of(e): RelationKind => [ Debuggable ],
}
let mut world = World::new();
let parent = Entity::builder()
.set(name(), "Alex".into())
.set(hobby(), "Sewing")
.attach_with(
child_of,
RelationKind::Dad,
Entity::builder()
.set(name(), "Eric".into())
.set(hobby(), "Gaming"),
)
.attach_with(
child_of,
RelationKind::Dad,
Entity::builder()
.set(name(), "Vanessa".into())
.set(hobby(), "Climbing"),
)
.spawn(&mut world);
assert_eq!(
world.get(parent, name()).as_deref(),
Ok(&"Alex".to_string())
);
let mut query = Query::new((name(), child_of(parent)));
let mut query = query.borrow(&world);
let children = query.iter().sorted().collect_vec();
assert_eq!(
children,
[
(&"Eric".to_string(), &RelationKind::Dad),
(&"Vanessa".to_string(), &RelationKind::Dad)
]
);
}
#[test]
fn hierarchy_manipulation() {
let mut world = World::new();
let a = Entity::builder()
.set(name(), "a".into())
.attach(child_of, Entity::builder().set(name(), "a.a".into()))
.spawn(&mut world);
let b = Entity::builder()
.set(name(), "b".into())
.attach(child_of, Entity::builder().set(name(), "b.a".into()))
.attach(child_of, Entity::builder().set(name(), "b.b".into()))
.spawn(&mut world);
let mut q = Query::new(entity_ids()).without_relation(child_of);
let roots = q.borrow(&world).iter().sorted().collect_vec();
assert_eq!(roots, [a, b]);
world.set(a, child_of(b), ()).unwrap();
let roots = q.borrow(&world).iter().sorted().collect_vec();
assert_eq!(roots, [b]);
world.detach(b);
assert_eq!(world.get(b, name()).as_deref(), Ok(&"b".to_string()));
let mut q = Query::new(name()).without_relation(child_of);
let mut roots = q.borrow(&world);
let roots = roots.iter().sorted().collect_vec();
assert_eq!(roots, ["a", "b", "b.a", "b.b"]);
let children_of_a = Query::new(name().cloned())
.with(child_of(a))
.collect_vec(&world);
let children_of_b = Query::new(name().cloned())
.with(child_of(b))
.collect_vec(&world);
assert_eq!(children_of_a, ["a.a"]);
assert_eq!(children_of_b, [""; 0]);
}