Authors: @doot Contributors: @bushRAT @quartermeister @Diddykonga @Victoron
This document details an alternative design to Unified EntityPtr Types.
We have a few types within Bevy ECS that allow access to an Entity's metadata and components:
EntityRef
: provides read-only access.EntityMut
: provides mutable access.EntityWorldMut
: provides structurally mutable access, like adding/removing components or despawning.However, we incur API duplication because these are unique types even though they only differ in semantics (they are essentially layout and alignment-compatible). If we can either 1. safely treat them as a single type for certain operations, or 2. eliminate the need for explicit conversions, we can reduce this duplication. This document attempts #2.
EntityView
To reduce API duplication we can try to implement a Deref "ladder" following: EntityWorldMut
-> EntityMut
-> EntityRef
. However, that creates a soundness issue that we'll describe below:
So, enter EntityView
:
It's almost exactly what EntityRef
currently is except it doesn't impl Clone
or Copy
, which means we can deref EntityMut
into it without causing UB. To keep things simple we'll also deref EntityRef
into it, which leaves us with two separate Deref
"ladders":
EntityWorldMut
-> EntityMut
-> EntityView
EntityRef
-> EntityView
And if users want to go from EntityMut
-> EntityRef
or EntityRef
<-> EntityView
, we'll still provide From
/Into
implementations for those conversions. However, those follow a &'a EntityMut<'w>
-> EntityRef<'a>
conversion (i.e. following the current lifetime shortening we use) so we don't introduce any UB. See the Public API Definition below for a more complete look.
The TL;DR is that impl<'w> Deref for EntityMut<'w> { type Target = EntityRef<'w>; }
is unsound because impl Clone for EntityRef
so we need a new type that's like EntityRef
but doesn't implement Clone
or Copy
.