use std::{cell::RefCell, rc::Rc};
use wasm_bindgen::UnwrapThrowExt;
use super::{FnMap, FnMapC};
pub struct QrVal<T>(Rc<RefCell<ValueContent<T>>>);
pub struct QrValMap<T, U> {
value: QrVal<T>,
fn_map: FnMap<T, U>,
}
pub struct QrValMapWithState<C, T, U> {
value: QrVal<T>,
fn_map: FnMapC<C, T, U>,
}
impl<T, U> QrValMap<T, U> {
pub fn into_parts(self) -> (QrVal<T>, FnMap<T, U>) {
(self.value, self.fn_map)
}
}
impl<C, T, U> QrValMapWithState<C, T, U> {
pub fn into_parts(self) -> (QrVal<T>, FnMapC<C, T, U>) {
(self.value, self.fn_map)
}
}
pub struct ValueContent<T> {
value: T,
a_render_is_queued: bool,
renders: Vec<Box<dyn QueueRender<T>>>,
}
impl<T> ValueContent<T> {
pub fn value(&self) -> &T {
&self.value
}
pub fn add_render(&mut self, r: Box<dyn QueueRender<T>>) {
self.renders.push(r);
}
fn render(&mut self) {
for r in self.renders.iter_mut() {
r.render(&self.value)
}
self.a_render_is_queued = false;
}
fn need_to_queue_a_render(&mut self) -> bool {
if self.a_render_is_queued {
return false;
}
self.a_render_is_queued = true;
true
}
}
impl<T> From<T> for QrVal<T> {
fn from(t: T) -> Self {
QrVal(Rc::new(RefCell::new(ValueContent {
value: t,
a_render_is_queued: false,
renders: Vec::new(),
})))
}
}
impl<T: 'static> QrVal<T> {
pub(crate) fn content(&self) -> &Rc<RefCell<ValueContent<T>>> {
&self.0
}
}
impl<T: 'static + PartialEq + Copy> QrVal<T> {
pub fn get(&self) -> T {
self.0
.try_borrow()
.expect_throw("Borrow for getting T")
.value
}
}
impl<T: 'static + PartialEq> QrVal<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
fn queue_me(&self, queue_me: bool) {
if queue_me {
let this = self.clone();
super::queue_render(move || this.render());
}
}
pub fn set(&mut self, t: T) {
let queue_me = match self.0.try_borrow_mut() {
Ok(mut this) if t != this.value => {
this.value = t;
this.need_to_queue_a_render()
}
Ok(_) => false,
Err(e) => {
log::error!("{}", e);
return;
}
};
self.queue_me(queue_me);
}
pub fn set_with(&mut self, ft: impl FnOnce(&T) -> T) {
let queue_me = match self.0.try_borrow_mut() {
Ok(mut this) => {
let t = ft(&this.value);
if t == this.value {
false
} else {
this.value = t;
this.need_to_queue_a_render()
}
}
Err(e) => {
log::error!("{}", e);
return;
}
};
self.queue_me(queue_me);
}
fn render(&self) {
match self.0.try_borrow_mut() {
Ok(mut this) => this.render(),
Err(e) => log::error!("queue_render::value::Value::render: {}", e),
}
}
pub fn map<U, F>(&self, fn_map: F) -> QrValMap<T, U>
where
F: 'static + Fn(&T) -> U,
{
QrValMap {
value: self.clone(),
fn_map: Box::new(fn_map),
}
}
pub fn map_with_state<C, U, F>(&self, fn_map: F) -> QrValMapWithState<C, T, U>
where
F: 'static + Fn(&C, &T) -> U,
{
QrValMapWithState {
value: self.clone(),
fn_map: Box::new(fn_map),
}
}
}
pub trait QueueRender<T> {
fn render(&mut self, t: &T);
fn unmounted(&self) -> bool;
}