use core::{marker::PhantomData, ptr::NonNull};
use crate::world::WorldLocal;
#[cfg(not(feature = "std"))]
use crate::nostd::flow::{
edict_get_flow_world_tls, edict_reset_flow_world_tls, edict_set_flow_world_tls,
};
#[cfg(feature = "std")]
std::thread_local! {
static WORLD_TLS: std::cell::Cell<Option<NonNull<WorldLocal>>> = const { std::cell::Cell::new(None) };
}
pub struct WorldGuard<'a> {
this: NonNull<WorldLocal>,
prev: Option<NonNull<WorldLocal>>,
marker: PhantomData<&'a mut WorldLocal>,
}
impl<'a> WorldGuard<'a> {
pub fn new(world: &'a mut WorldLocal) -> Self {
let this = NonNull::from(world);
#[cfg(feature = "std")]
let prev = WORLD_TLS.with(|cell| cell.replace(Some(this)));
#[cfg(not(feature = "std"))]
let prev = unsafe { edict_set_flow_world_tls(this.cast()).map(NonNull::cast) };
WorldGuard {
this,
prev,
marker: PhantomData,
}
}
}
impl Drop for WorldGuard<'_> {
fn drop(&mut self) {
#[cfg(feature = "std")]
WORLD_TLS.with(|cell| {
let top = cell.replace(self.prev);
debug_assert_eq!(top, Some(self.this));
});
#[cfg(not(feature = "std"))]
unsafe {
edict_reset_flow_world_tls(self.prev.map(NonNull::cast), self.this.cast());
}
}
}
pub(super) unsafe fn get_world_mut<'a>() -> &'a mut WorldLocal {
#[cfg(feature = "std")]
let world = WORLD_TLS.with(|cell| cell.get());
#[cfg(not(feature = "std"))]
let world = unsafe { edict_get_flow_world_tls() }.map(NonNull::cast);
unsafe { world.unwrap().as_mut() }
}