use nexus_rt::World;
#[derive(Clone, Copy)]
pub struct WorldCtx {
ptr: *mut World,
}
impl WorldCtx {
pub fn new(world: &mut World) -> Self {
Self {
ptr: world as *mut World,
}
}
pub(crate) fn as_ptr(&self) -> *mut World {
self.ptr
}
pub fn with_world<R>(&self, f: impl FnOnce(&mut World) -> R) -> R {
let world = unsafe { &mut *self.ptr };
f(world)
}
pub fn with_world_ref<R>(&self, f: impl FnOnce(&World) -> R) -> R {
let world = unsafe { &*self.ptr };
f(world)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Executor;
use nexus_rt::{Handler, IntoHandler, Res, ResMut, WorldBuilder};
nexus_rt::new_resource!(Val(u64));
nexus_rt::new_resource!(Out(u64));
#[test]
fn with_world_raw_access() {
let mut wb = WorldBuilder::new();
wb.register(Val(42));
wb.register(Out(0));
let mut world = wb.build();
let ctx = WorldCtx::new(&mut world);
let mut executor = Executor::new(4);
executor.spawn_boxed(async move {
ctx.with_world(|world| {
let v = world.resource::<Val>().0;
world.resource_mut::<Out>().0 = v + 10;
});
});
executor.drain();
assert_eq!(world.resource::<Out>().0, 52);
}
#[test]
fn with_world_ref_read_only() {
let mut wb = WorldBuilder::new();
wb.register(Val(99));
let mut world = wb.build();
let ctx = WorldCtx::new(&mut world);
let result = std::cell::Cell::new(0u64);
let result_ptr = &result as *const std::cell::Cell<u64>;
let mut executor = Executor::new(4);
executor.spawn_boxed(async move {
let v = ctx.with_world_ref(|world| world.resource::<Val>().0);
unsafe { &*result_ptr }.set(v);
});
executor.drain();
assert_eq!(result.get(), 99);
}
#[test]
fn with_world_pre_resolved_handler() {
let mut wb = WorldBuilder::new();
wb.register(Val(42));
wb.register(Out(0));
let mut world = wb.build();
let ctx = WorldCtx::new(&mut world);
let mut handler = (|val: Res<Val>, mut out: ResMut<Out>, event: u64| {
out.0 = val.0 + event;
})
.into_handler(world.registry());
let mut executor = Executor::new(4);
executor.spawn_boxed(async move {
ctx.with_world(|world| handler.run(world, 10));
});
executor.drain();
assert_eq!(world.resource::<Out>().0, 52);
}
#[test]
fn with_world_returns_value() {
let mut wb = WorldBuilder::new();
wb.register(Val(7));
let mut world = wb.build();
let ctx = WorldCtx::new(&mut world);
let result = std::cell::Cell::new(0u64);
let result_ptr = &result as *const std::cell::Cell<u64>;
let mut executor = Executor::new(4);
executor.spawn_boxed(async move {
let v = ctx.with_world(|world| {
world.resource::<Val>().0 * 6
});
unsafe { &*result_ptr }.set(v);
});
executor.drain();
assert_eq!(result.get(), 42);
}
#[test]
fn multiple_tasks_share_ctx() {
let mut wb = WorldBuilder::new();
wb.register(Out(0));
let mut world = wb.build();
let ctx = WorldCtx::new(&mut world);
let mut executor = Executor::new(4);
for i in 1..=3u64 {
let ctx = ctx; executor.spawn_boxed(async move {
ctx.with_world(|world| {
world.resource_mut::<Out>().0 += i;
});
});
}
executor.drain();
assert_eq!(world.resource::<Out>().0, 6); }
}