I noticed that CoercePointee only works for pointers, but I have been thinking that it could be beneficial if it allowed other types aside pointers.
I believe that this example would be a good use case for it:
// The attribute syntax is only a sketch. What matters is that the key carries the vtable.
#[derive(CoercePointee)]
struct CastKey<T: ?Sized> {
key: Key,
#[metadata]
metadata: <T as Pointee>::Metadata,
}
trait Entity {
fn on_hit(self: CastKey<Self>, world: &mut World, damage: u32);
}
struct Barrel {
health: u32,
position: Vec2,
}
impl Entity for Barrel {
fn on_hit(self: CastKey<Self>, world: &mut World, damage: u32) {
let barrel : &mut Barrel = &mut world[self];
barrel.health = barrel.health.saturating_sub(damage);
if barrel.health == 0 {
let center = barrel.position;
world.remove(self);
// Explosion!
world.hit_all_near(center, 5.0, 50);
}
}
}
while let Some((target, damage)) = world.hits.pop() {
target.on_hit(&mut world, damage);
}
Calling a trait method on an entity stored in an arena means borrowing it from the world as a &mut dyn Entity, because that reference holds the vtable. However, that borrow basically locks the whole world, so the method can't also take &mut World.
If the key holds the vtable instead, you can call the method on the key and nothing is borrowed from the world. The method gets the key and &mut World as separate arguments, so the borrow checker has nothing to complain about.
What do you think?