use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
pub struct State<T> {
inner: Rc<StateInner<T>>,
}
struct StateInner<T> {
value: RefCell<T>,
dirty: RefCell<bool>,
}
impl<T> Clone for State<T> {
fn clone(&self) -> Self {
Self {
inner: Rc::clone(&self.inner),
}
}
}
impl<T> State<T> {
pub fn new(value: T) -> Self {
Self {
inner: Rc::new(StateInner {
value: RefCell::new(value),
dirty: RefCell::new(false),
}),
}
}
pub fn get(&self) -> T
where
T: Clone,
{
self.inner.value.borrow().clone()
}
pub fn set(&self, value: T) {
*self.inner.value.borrow_mut() = value;
*self.inner.dirty.borrow_mut() = true;
}
pub fn update(&self, f: impl FnOnce(&mut T)) {
f(&mut self.inner.value.borrow_mut());
*self.inner.dirty.borrow_mut() = true;
}
pub fn is_dirty(&self) -> bool {
*self.inner.dirty.borrow()
}
pub fn clear_dirty(&self) {
*self.inner.dirty.borrow_mut() = false;
}
pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
f(&self.inner.value.borrow())
}
}
impl<T: fmt::Display> fmt::Display for State<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.value.borrow().fmt(f)
}
}
impl<T: fmt::Debug> fmt::Debug for State<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("State")
.field(&*self.inner.value.borrow())
.finish()
}
}