use std::cell::{Cell, RefCell};
use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SurfaceHandle(pub u64);
impl SurfaceHandle {
pub const NONE: SurfaceHandle = SurfaceHandle(0);
pub fn is_none(self) -> bool {
self.0 == 0
}
pub fn enter(self) -> SurfaceEnterGuard {
if self == current_surface() {
return SurfaceEnterGuard::noop();
}
let hook = ENTER_HOOK.with(|h| h.borrow().clone());
match hook {
Some(f) => f(self),
None => SurfaceEnterGuard::noop(),
}
}
}
impl Default for SurfaceHandle {
fn default() -> Self {
Self::NONE
}
}
thread_local! {
static CURRENT_SURFACE: Cell<SurfaceHandle> = const { Cell::new(SurfaceHandle::NONE) };
static ENTER_HOOK: RefCell<Option<Rc<dyn Fn(SurfaceHandle) -> SurfaceEnterGuard>>> =
const { RefCell::new(None) };
}
pub fn current_surface() -> SurfaceHandle {
CURRENT_SURFACE.with(|c| c.get())
}
pub fn set_current_surface(handle: SurfaceHandle) -> SurfaceHandle {
CURRENT_SURFACE.with(|c| c.replace(handle))
}
pub fn set_surface_enter_hook(f: impl Fn(SurfaceHandle) -> SurfaceEnterGuard + 'static) {
ENTER_HOOK.with(|h| *h.borrow_mut() = Some(Rc::new(f)));
}
#[must_use = "the surface context is only active while this guard is alive"]
pub struct SurfaceEnterGuard {
restore: Option<Box<dyn FnOnce()>>,
}
impl SurfaceEnterGuard {
pub fn noop() -> Self {
Self { restore: None }
}
pub fn new(restore: impl FnOnce() + 'static) -> Self {
Self {
restore: Some(Box::new(restore)),
}
}
}
impl Drop for SurfaceEnterGuard {
fn drop(&mut self) {
if let Some(f) = self.restore.take() {
f();
}
}
}