use metriken_core::Window;
use parking_lot::RwLock;
use std::sync::OnceLock;
#[derive(Default, Debug)]
pub(crate) struct WindowCell {
inner: OnceLock<Box<RwLock<Option<Window>>>>,
}
impl WindowCell {
pub(crate) const fn new() -> Self {
Self {
inner: OnceLock::new(),
}
}
fn get_or_init(&self) -> &RwLock<Option<Window>> {
self.inner.get_or_init(|| Box::new(RwLock::new(None)))
}
pub(crate) fn with_write<R>(&self, f: impl FnOnce(&mut Option<Window>) -> R) -> R {
let mut guard = self.get_or_init().write();
f(&mut guard)
}
pub(crate) fn with_read<R>(&self, f: impl FnOnce(Option<Window>) -> R) -> R {
match self.inner.get() {
Some(lock) => {
let guard = lock.read();
f(*guard)
}
None => f(None),
}
}
pub(crate) fn load(&self) -> Option<Window> {
self.inner.get().and_then(|lock| *lock.read())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unset_does_not_allocate_and_reads_none() {
let cell = WindowCell::new();
assert!(cell.load().is_none());
assert_eq!(cell.with_read(|w| w), None);
assert!(cell.inner.get().is_none(), "with_read must not allocate");
}
#[test]
fn write_then_read_round_trips() {
let cell = WindowCell::new();
cell.with_write(|w| *w = Some(Window::new(10, 20)));
assert_eq!(cell.load(), Some(Window::new(10, 20)));
assert_eq!(cell.with_read(|w| w), Some(Window::new(10, 20)));
}
}