#Using UnsafeWorldCell safely

6 messages · Page 1 of 1 (latest)

devout night
#
#[derive(Component, Debug)]
struct Value(u32);

trait Mutable {
    fn update() -> Box<dyn System<In = Mut<'static, Self>, Out = ()>>;
}

#[derive(Component)]
struct CloneValues {
    values: Vec<u32>,
}

impl Mutable for CloneValues {
    fn update() -> Box<dyn System<In = Mut<'static, Self>, Out = ()>> {
        Box::new(bevy::ecs::system::IntoSystem::into_system(
            |this: In<Mut<Self>>, values: Query<(Entity, &Value)>| {
                let mut this = this.0;

                this.values.clear();

                for (entity, value) in &values {
                    info!("{:?}: Adding Value {:?}", entity, value);
                    this.values.push(value.0);
                }
            },
        ))
    }
}

fn run_clone_values(world: &mut World) {
    let id = world.component_id::<CloneValues>().unwrap();

    let access = {
        let mut a = Access::new();
        a.add_write(id);
        a
    };

    let mut system = CloneValues::update();

    // SAFETY: we must make sure the system's access does not include CloneValues
    assert!(access.is_compatible(system.component_access()));

    let cell = world.as_unsafe_world_cell();

    // SAFETY: this will only be used to query for CloneValues
    let query_world = unsafe { cell.world_mut() };
    // SAFETY: this will only be used by the system
    let system_world = unsafe { cell.world_mut() };

    // At this point we have multiple exclusive references to world

    let mut query = query_world.query::<&mut CloneValues>();

    system.initialize(system_world);

    for comp in query.iter_mut(query_world) {
        // SAFETY: system does not outlive world
        let input: Mut<'static, CloneValues> = unsafe { std::mem::transmute(comp) };
        system.run(input, system_world);
    }
}

Is there a better way to do this?

bold gull
#

Having multiple &mut World s is definitely UB

#

You should at least be using system.run_unsafe

#

There's probably a less convoluted way of doing this, but I'm not sure what you're trying to do

devout night
bold gull
#

yeah, iter_unchecked is probably the way to go. Then your safety is just that the two queries don't overlap.