You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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)]structFoo(u8);#[derive(Component)]structLikes;#[derive(Component)]structAlice;#[derive(Component)]structBob;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(|_| {/* ... */});
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.
(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.
The text was updated successfully, but these errors were encountered:
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.
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 withInvariant
cannot query for data components & also cannot be cached. It also acts likeDisabled
in that archetypes with this tag are excluded from queries by default.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 withoutNot
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.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 withInvariant, (Reads, Foo), (Writes, Bar)
. Before running it would first query forInvariant, 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 addsRunning
to its own associated entity describing its access which can be checked by other queries. It removesRunning
when the it is finished.(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 withInvariant
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.The text was updated successfully, but these errors were encountered: