#[macro_export]
macro_rules! surface_local {
(
$(#[$ctx_meta:meta])*
slot $slot:ident : $ty:ty = $init:expr;
access $with:ident, $with_ref:ident;
context $ctx:ident, $guard:ident;
) => {
thread_local! {
static $slot: ::std::cell::Cell<*mut ::std::cell::RefCell<$ty>> =
::std::cell::Cell::new(::std::boxed::Box::into_raw(::std::boxed::Box::new(
::std::cell::RefCell::new($init),
)));
}
#[allow(dead_code)]
fn $with<R>(f: impl ::std::ops::FnOnce(&mut $ty) -> R) -> R {
$slot.with(|cell| unsafe { f(&mut *(*cell.get()).borrow_mut()) })
}
#[allow(dead_code)]
fn $with_ref<R>(f: impl ::std::ops::FnOnce(&$ty) -> R) -> R {
$slot.with(|cell| unsafe { f(&*(*cell.get()).borrow()) })
}
$(#[$ctx_meta])*
pub struct $ctx {
ptr: *mut ::std::cell::RefCell<$ty>,
}
impl $ctx {
pub fn new() -> Self {
Self {
ptr: ::std::boxed::Box::into_raw(::std::boxed::Box::new(
::std::cell::RefCell::new($init),
)),
}
}
#[must_use = "the surface context is only active while this guard is alive"]
pub fn enter(&self) -> $guard {
let prev = $slot.with(|cell| cell.replace(self.ptr));
$guard { prev }
}
}
impl ::std::default::Default for $ctx {
fn default() -> Self {
Self::new()
}
}
impl ::std::ops::Drop for $ctx {
fn drop(&mut self) {
unsafe { drop(::std::boxed::Box::from_raw(self.ptr)) };
}
}
#[must_use = "the surface context is only active while this guard is alive"]
pub struct $guard {
prev: *mut ::std::cell::RefCell<$ty>,
}
impl ::std::ops::Drop for $guard {
fn drop(&mut self) {
$slot.with(|cell| cell.set(self.prev));
}
}
};
}