Skip to content

Commit

Permalink
feat: document exclusive relations
Browse files Browse the repository at this point in the history
  • Loading branch information
ten3roberts committed Oct 17, 2023
1 parent cf664d7 commit c2a15bb
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
42 changes: 40 additions & 2 deletions examples/guide/relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ use tracing_tree::HierarchicalLayer;

fn main() -> anyhow::Result<()> {
registry().with(HierarchicalLayer::default()).init();
basic()?;
exclusive()?;
Ok(())
}

fn basic() -> anyhow::Result<()> {
let mut world = World::new();

// ANCHOR: relation_basic
component! {
child_of(id): (),
}

let mut world = World::new();

let parent = Entity::builder()
.set(name(), "Parent".into())
.spawn(&mut world);
Expand Down Expand Up @@ -93,3 +98,36 @@ fn main() -> anyhow::Result<()> {

Ok(())
}

fn exclusive() -> anyhow::Result<()> {
let mut world = World::new();

// ANCHOR: exclusive
component! {
child_of(parent): () => [ Exclusive ],
}

let id1 = Entity::builder().spawn(&mut world);
let id2 = Entity::builder().spawn(&mut world);

let id3 = Entity::builder()
.set_default(child_of(id1))
.spawn(&mut world);

let entity = world.entity_mut(id3).unwrap();

tracing::info!(
"relations of {id3}: {:?}",
entity.relations(child_of).map(|v| v.0).collect_vec()
);

world.set(id3, child_of(id2), ()).unwrap();

let entity = world.entity_mut(id3).unwrap();
tracing::info!(
"relations of {id3}: {:?}",
entity.relations(child_of).map(|v| v.0).collect_vec()
);
// ANCHOR_END: exclusive
Ok(())
}
14 changes: 14 additions & 0 deletions guide/src/fundamentals/relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ The following shows a more complete example of how to traverse and calculate the
{{ #include ../../../examples/guide/springs.rs:main }}
```

# Exclusive relations

Relations can be declared as exclusive, which means that only one relation of that type can exist on an entity at a time. This is useful for cases where you want to have a single parent or outgoing connection.

**Note**: This does not prevent multiple entities from referencing the same entity, but rather an entity referencing multiple entities.

When a new relation is added to an entity, any existing relation of the same type will be removed.

This is the case for the included [`child_of`](https://docs.rs/flax/latest/flax/components/fn.child_of.html) relation.

```rust
{{ #include ../../../examples/guide/relations.rs:exclusive }}
```

## Lifetime

Relations are managed by the ECS and will automatically be cleaned up. When an entity is despawned all relations which reference it will be removed from the ECS. As such, a relation will never point to an invalid entity.
Expand Down
25 changes: 25 additions & 0 deletions tests/relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,28 @@ fn many_detach() {

world.despawn_recursive(parent, child_of).unwrap();
}

#[test]
fn exclusive() {
component! {
child_of(parent): () => [ Exclusive ],
}

let mut world = World::new();

let id1 = Entity::builder().spawn(&mut world);
let id2 = Entity::builder().spawn(&mut world);

let id3 = Entity::builder()
.set_default(child_of(id1))
.spawn(&mut world);

let entity = world.entity_mut(id3).unwrap();

assert_eq!(entity.relations(child_of).map(|v| v.0).collect_vec(), [id1]);

world.set(id3, child_of(id2), ()).unwrap();

let entity = world.entity_mut(id3).unwrap();
assert_eq!(entity.relations(child_of).map(|v| v.0).collect_vec(), [id2])
}

0 comments on commit c2a15bb

Please sign in to comment.