pub unsafe trait LendJoin: for<'next> LendJoinඞType<'next> {
type Value;
type Mask: BitSetLike;
// Required methods
unsafe fn open(self) -> (Self::Mask, Self::Value);
unsafe fn get<'next>(
value: &'next mut Self::Value,
id: Index
) -> <Self as LendJoinඞType<'next>>::T;
// Provided methods
fn lend_join(self) -> JoinLendIter<Self>
where Self: Sized { ... }
fn maybe(self) -> MaybeJoin<Self>
where Self: Sized { ... }
fn is_unconstrained() -> bool { ... }
}
Expand description
Like the Join
trait except this is similar to a lending
iterator
in that only one item can be accessed at once.
The type returned from .lend_join()
,
JoinLendIter
does not implement Iterator
like
JoinIter
does. Instead, it provides a
next
method that exclusively borrows the
JoinLendIter
for the lifetime of the returned value.
This limitation allows freedom for more patterns to be soundly implemented.
Thus, LendJoin
acts as the “lowest common denominator” of the
Join
-like traits (i.e. if something can implement Join
it can also
implement LendJoin
).
In particular, Entries
only implements
LendJoin
. As another example,
RestrictedStorage
implements both
Join
and LendJoin
. However, for joining mutably, lend join variant
produces
PairedStorageWriteExclusive
values which have get_other
/get_other_mut
methods that aren’t provided
by PairedStorageWriteShared
.
Finally, these limitations allow providing the JoinLendIter::get
method
which can be useful to get a set of components from an entity without
calling get
individually on each storage (see the example in that method’s
docs).
Also see the lend_join
example.
Safety
The Self::Mask
value returned with the Self::Value
must correspond such
that it is safe to retrieve items from Self::Value
whose presence is
indicated in the mask. As part of this, BitSetLike::iter
must not produce
an iterator that repeats an Index
value if the LendJoin::get
impl relies
on not being called twice with the same Index
.
Required Associated Types§
sourcetype Mask: BitSetLike
type Mask: BitSetLike
Type of joined bit mask.
Required Methods§
sourceunsafe fn open(self) -> (Self::Mask, Self::Value)
unsafe fn open(self) -> (Self::Mask, Self::Value)
Open this join by returning the mask and the storages.
Safety
This is unsafe because implementations of this trait can permit the
Value
to be mutated independently of the Mask
. If the Mask
does
not correctly report the status of the Value
then illegal memory
access can occur.
sourceunsafe fn get<'next>(
value: &'next mut Self::Value,
id: Index
) -> <Self as LendJoinඞType<'next>>::T
unsafe fn get<'next>( value: &'next mut Self::Value, id: Index ) -> <Self as LendJoinඞType<'next>>::T
Get a joined component value by a given index.
Safety
- A call to
get
must be preceded by a check ifid
is part ofSelf::Mask
- Multiple calls with the same
id
are not allowed, for a particular instance of the values fromopen
. Unless this type implements the unsafe traitRepeatableLendGet
.
Provided Methods§
sourcefn lend_join(self) -> JoinLendIter<Self>where
Self: Sized,
fn lend_join(self) -> JoinLendIter<Self>where Self: Sized,
Create a joined lending iterator over the contents.
sourcefn maybe(self) -> MaybeJoin<Self>where
Self: Sized,
fn maybe(self) -> MaybeJoin<Self>where Self: Sized,
Returns a structure that implements Join
/LendJoin
/MaybeJoin
if the
contained T
does and that yields all indices, returning None
for all
missing elements and Some(T)
for found elements.
To join over and optional component mutably this pattern can be used:
(&mut storage).maybe()
.
WARNING: Do not have a join of only MaybeJoin
s. Otherwise the join
will iterate over every single index of the bitset. If you want a
join with all MaybeJoin
s, add an EntitiesRes
to the join as well
to bound the join to all entities that are alive.
struct ExampleSystem;
impl<'a> System<'a> for ExampleSystem {
type SystemData = (
WriteStorage<'a, Pos>,
ReadStorage<'a, Vel>,
);
fn run(&mut self, (mut positions, velocities): Self::SystemData) {
let mut join = (&mut positions, velocities.maybe()).lend_join();
while let Some ((mut position, maybe_velocity)) = join.next() {
if let Some(velocity) = maybe_velocity {
position.x += velocity.x;
position.y += velocity.y;
}
}
}
}
fn main() {
let mut world = World::new();
let mut dispatcher = DispatcherBuilder::new()
.with(ExampleSystem, "example_system", &[])
.build();
dispatcher.setup(&mut world);
let e1 = world.create_entity()
.with(Pos { x: 0, y: 0 })
.with(Vel { x: 5, y: 2 })
.build();
let e2 = world.create_entity()
.with(Pos { x: 0, y: 0 })
.build();
dispatcher.dispatch(&mut world);
let positions = world.read_storage::<Pos>();
assert_eq!(positions.get(e1), Some(&Pos { x: 5, y: 2 }));
assert_eq!(positions.get(e2), Some(&Pos { x: 0, y: 0 }));
}
sourcefn is_unconstrained() -> bool
fn is_unconstrained() -> bool
If this LendJoin
typically returns all indices in the mask, then
iterating over only it or combined with other joins that are also
dangerous will cause the JoinLendIter
to go through all indices which
is usually not what is wanted and will kill performance.