use std::cell::RefCell;
use std::marker::PhantomData;
use std::rc::Rc;
use crate::Context;
use crate::KeepLatest;
use crate::context::{Compute, ComputeOps, SlotId};
use crate::effect::Effect;
use crate::merge::MergePolicy;
pub struct Source<T, M = KeepLatest> {
pub(crate) id: SlotId,
pub(crate) _marker: PhantomData<(T, M)>,
}
impl<T, M> Source<T, M> {
pub(crate) fn from_id(id: SlotId) -> Self {
Self {
id,
_marker: PhantomData,
}
}
pub fn get<C: ComputeOps>(&self, ctx: &C) -> T
where
T: Clone + 'static,
{
ctx.read_value::<T>(self.id)
}
pub fn dispose<C: ComputeOps>(&self, ctx: &C)
where
T: 'static,
{
ctx.dispose_node(self.id);
}
pub fn subscribe(&self, ctx: &Context, on_change: impl FnMut(&Compute, &T) + 'static) -> Effect
where
T: Clone + 'static,
M: 'static,
{
let this = *self;
let cb = RefCell::new(on_change);
ctx.effect(move |c| {
let v = this.get(c);
(cb.borrow_mut())(c, &v);
})
}
}
impl<T, M: MergePolicy<T>> Source<T, M> {
pub fn set(&self, ctx: &Context, value: T)
where
T: PartialEq + 'static,
{
ctx.set_source::<T>(self.id, value);
}
pub fn merge(&self, ctx: &Context, op: T)
where
T: PartialEq + Clone + 'static,
{
ctx.merge_source::<T, M>(self.id, op);
}
pub fn cell(&self) -> Source<T> {
Source::from_id(self.id)
}
pub fn clear_dependents(&self, ctx: &Context) {
ctx.clear_cell_dependents(self.id);
}
}
impl<T, M> Clone for Source<T, M> {
fn clone(&self) -> Self {
*self
}
}
impl<T, M> Copy for Source<T, M> {}
impl<T, M> PartialEq for Source<T, M> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T, M> Eq for Source<T, M> {}
impl<T, M> std::fmt::Debug for Source<T, M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Source").field("id", &self.id).finish()
}
}
pub struct Computed<T> {
pub(crate) id: SlotId,
pub(crate) _marker: PhantomData<T>,
}
impl<T> Computed<T> {
pub(crate) fn from_id(id: SlotId) -> Self {
Self {
id,
_marker: PhantomData,
}
}
pub fn get<C: ComputeOps>(&self, ctx: &C) -> T
where
T: Clone + 'static,
{
ctx.read_value::<T>(self.id)
}
pub fn get_rc<C: ComputeOps>(&self, ctx: &C) -> Rc<T>
where
T: 'static,
{
ctx.get_rc(self)
}
pub fn dispose<C: ComputeOps>(&self, ctx: &C)
where
T: 'static,
{
ctx.dispose_node(self.id);
}
pub fn subscribe(&self, ctx: &Context, on_change: impl FnMut(&Compute, &T) + 'static) -> Effect
where
T: Clone + 'static,
{
let this = *self;
let cb = RefCell::new(on_change);
ctx.effect(move |c| {
let v = this.get(c);
(cb.borrow_mut())(c, &v);
})
}
pub fn clear(&self, ctx: &Context) {
ctx.clear_slot(self.id);
ctx.flush_effects_after_invalidation();
}
pub fn eager(&self, ctx: &Context) -> Self
where
T: 'static,
{
ctx.make_eager::<T>(self.id);
*self
}
pub fn lazy(&self, ctx: &Context) {
ctx.make_lazy(self.id);
}
pub fn is_eager(&self, ctx: &Context) -> bool {
ctx.is_eager(self.id)
}
}
impl<T> Clone for Computed<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Computed<T> {}
impl<T> PartialEq for Computed<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T> Eq for Computed<T> {}
impl<T> std::fmt::Debug for Computed<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Computed").field("id", &self.id).finish()
}
}