#[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<$crate::SurfaceSlot<$ty>> = {
let ambient = ::std::boxed::Box::into_raw(::std::boxed::Box::new(
::std::cell::RefCell::new($init),
));
::std::cell::Cell::new($crate::SurfaceSlot { live: ambient, ambient })
};
}
#[allow(dead_code)]
fn $with<R>(f: impl ::std::ops::FnOnce(&mut $ty) -> R) -> R {
$slot.with(|cell| unsafe { f(&mut *(*cell.get().live).borrow_mut()) })
}
#[allow(dead_code)]
fn $with_ref<R>(f: impl ::std::ops::FnOnce(&$ty) -> R) -> R {
$slot.with(|cell| unsafe { f(&*(*cell.get().live).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 {
$guard {
prev: $slot.with(|cell| {
let mut slot = cell.get();
let prev = ::std::mem::replace(&mut slot.live, self.ptr);
cell.set(slot);
prev
}),
}
}
#[must_use = "the surface context is only active while this guard is alive"]
pub fn enter_ambient() -> $guard {
$guard {
prev: $slot.with(|cell| {
let mut slot = cell.get();
let prev = ::std::mem::replace(&mut slot.live, slot.ambient);
cell.set(slot);
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| {
let mut slot = cell.get();
slot.live = self.prev;
cell.set(slot);
});
}
}
};
}
#[doc(hidden)]
pub struct SurfaceSlot<T> {
pub live: *mut std::cell::RefCell<T>,
pub ambient: *mut std::cell::RefCell<T>,
}
impl<T> Clone for SurfaceSlot<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for SurfaceSlot<T> {}