Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Invariant" tags, queries & archetypes #1529

Open
iiYese opened this issue Jan 22, 2025 · 0 comments
Open

"Invariant" tags, queries & archetypes #1529

iiYese opened this issue Jan 22, 2025 · 0 comments
Labels
enhancement New feature or request

Comments

@iiYese
Copy link

iiYese commented Jan 22, 2025

Describe the problem you are trying to solve.

I originally had this thought as a potential solution to implementing column locks for the rust binding which requires XOR mut aliasing. After playing with the idea more however it seemed like it could be a generally useful tool for evaluating predicates even if its unoptimal for column locks.

Describe the solution you'd like

New special "Invariant" tags to describe & query for predicates with the ECS.

  1. Invariant: When this is used as a tag on an archetype that archetype cannot have data components. Adding or removing components from these archetypes is not considered a structural change since they will never have tables meaning changes to invariant entities are always immediate. Queries with Invariant cannot query for data components & also cannot be cached. It also acts like Disabled in that archetypes with this tag are excluded from queries by default.
#[derive(Component)]
struct Foo(u8);

#[derive(Component)]
struct Likes;

#[derive(Component)]
struct Alice;

#[derive(Component)]
struct Bob;

let e = world.entity()
    .add::<Invariant>()
    .add::<Alice>()
    .add_first::<Likes>(Bob);

assert!(query!(world, Invariant, Alice, (Likes, Bob)).build().is_true());

// these will all panic
e.set(Foo(0));
world.entity(Foo(0)).add::<Invariant>();
query!(world, Invariant, &Foo).build();
query!(world, Invariant).set_cached().build();
query!(world, Invariant).build().each(|_| { /* ... */ });
  1. Not: By default an invariant archetype that describes a predicate is "upheld" if it has at least 1 match. This negates that & makes it so the invariant is "upheld" if there are exactly 0 matches. When used in a query without Not being present on the archetype it negates the result. When used in a archetype it negates the result for all queries. When used in both it's a double negation.
let e = world.entity()
    .add::<Invariant>()
    .add::<Alice>()
    .add::<Likes>(Bob);

assert!(query!(world, Invariant, Alice, (Likes, Bob)).build().is_true());
assert!(query!(world, Invariant, Not, Alice, (Likes, Bob)).build().is_false());

e.add::<Not>();
assert!(query!(world, Invariant, Alice, (Likes, Bob)).build().is_false());
assert!(query!(world, Invariant, Not, Alice, (Likes, Bob)).build().is_true());

Putting 1 & 2 together an example of how this could be used is column locks. A query accessing &Foo, &mut Bar would have an associated entity with Invariant, (Reads, Foo), (Writes, Bar). Before running it would first query for Invariant, Not, (Read, Foo), (Writes, Bar) || (Reads, Bar), Running. If there is a single result we have conflicting access & we can panic. If there isn't it adds Running to its own associated entity describing its access which can be checked by other queries. It removes Running when the it is finished.

  1. (Invariant, *): When an entity that has an (Invariant, *) pair is accessed or matched by a query the invariant described by * is also evaluated. Using the column lock example again cached queries could have (Invariant, *) pairs with the entity behind * describing their access. Archetypes with Invariant can also have (Invariant, *) to describe dependencies which allows for recursive predicate evaluation.

Todo/Follow up

Design semantics for variables, wildcards & logical AND + OR operators.

@iiYese iiYese added the enhancement New feature or request label Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant