use std::rc::Rc;
use vertigo_macro::bind;
use crate::{Context, DomNode, ToComputed, computed::value_inner::ValueInner};
use super::{Computed, DropResource, GraphId, dependencies::get_dependencies};
#[derive(Clone)]
pub struct Value<T: Clone + PartialEq + 'static> {
inner: Rc<ValueInner<T>>,
}
impl<T: Clone + PartialEq + Default + 'static> Default for Value<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: Clone + PartialEq> PartialEq for Value<T> {
fn eq(&self, other: &Self) -> bool {
self.inner.id.eq(&other.inner.id)
}
}
impl<T: Clone + PartialEq + 'static> ToComputed<T> for Value<T> {
fn to_computed(&self) -> Computed<T> {
self.to_computed()
}
}
impl<T: Clone + PartialEq + 'static> ToComputed<T> for &Value<T> {
fn to_computed(&self) -> Computed<T> {
(*self).to_computed()
}
}
impl<T: Clone + PartialEq + 'static> Value<T> {
pub fn new(value: T) -> Self {
Value {
inner: Rc::new(ValueInner::new(value)),
}
}
pub fn with_connect<F>(value: T, create: F) -> Computed<T>
where
F: Fn(&Value<T>) -> DropResource + 'static,
{
let value = Value::new(value);
let value_clone = value.clone();
value
.to_computed()
.when_connect(move || create(&value_clone))
}
pub fn get(&self, context: &Context) -> T {
context.add_parent(self.inner.id, self.inner.clone());
self.inner.get()
}
pub fn map<K: Clone + 'static, F: 'static + Fn(T) -> K>(&self, fun: F) -> Computed<K> {
Computed::from({
let myself = self.clone();
move |context| fun(myself.get(context))
})
}
pub fn id(&self) -> GraphId {
self.inner.id
}
pub fn to_computed(&self) -> Computed<T> {
let myself = self.clone();
Computed::from(move |context| myself.get(context))
}
pub fn change(&self, change_fn: impl FnOnce(&mut T)) {
get_dependencies().transaction(|ctx| {
let mut value = self.get(ctx);
change_fn(&mut value);
self.set(value);
});
}
pub fn set(&self, value: T) {
get_dependencies().transaction(|_| {
let need_refresh = self.inner.set(value);
if need_refresh {
get_dependencies().report_set(self.inner.id);
}
});
}
pub fn render_value(&self, render: impl Fn(T) -> DomNode + 'static) -> DomNode {
self.to_computed().render_value(render)
}
pub fn render_value_option(&self, render: impl Fn(T) -> Option<DomNode> + 'static) -> DomNode {
self.to_computed().render_value_option(render)
}
pub fn add_event(&self, callback: impl Fn(T) + 'static) -> DropResource {
self.inner.add_event(callback)
}
pub fn synchronize<R: ValueSynchronize<T> + Clone + 'static>(&self) -> (R, DropResource) {
let init_value = self.inner.get();
let synchronize_target = R::new(init_value);
let drop_synchronize = self.add_event(bind!(synchronize_target, |current| {
synchronize_target.set(current);
}));
(synchronize_target, drop_synchronize)
}
}
pub trait ValueSynchronize<T: PartialEq + Clone + 'static>: Sized {
fn new(value: T) -> Self;
fn set(&self, value: T);
}