rsconnect 0.2.2

Fine-grained reactivity in Rust
Documentation
use std::{
	cell::{Ref, RefCell},
	marker::PhantomData,
	rc::Rc,
};

use crate::{
	comparable_value::{ComparableValue, NonComparableValue, Value},
	connect_structs::Connect,
	node_traits::{
		ComputedNode, ConnectNode, DynComputedNode, DynNode, Node, NodeValueAccess,
		WeakDynComputedNode,
	},
};

pub type ConnectObserved<T> = Rc<RefCell<Observed<T, ComparableValue<T>>>>;

pub type ConnectObservedAny<T> = Rc<RefCell<Observed<T, NonComparableValue<T>>>>;

pub type ConnectComputed<T, F> = Rc<RefCell<Computed<T, ComparableValue<T>, F>>>;

pub type ConnectComputedAny<T, F> = Rc<RefCell<Computed<T, NonComparableValue<T>, F>>>;

pub type ConnectEffected<T, F, E> = Rc<RefCell<Effected<T, ComparableValue<T>, F, E>>>;

pub type ConnectEffectedAny<T, F, E> =
	Rc<RefCell<Effected<T, NonComparableValue<T>, F, E>>>;

pub struct Observed<T, V: Value<T>> {
	value: V,
	derived: Vec<WeakDynComputedNode>,
	value_type: PhantomData<T>,
}

impl<T: PartialEq> Observed<T, ComparableValue<T>> {
	pub(crate) fn new(value: T) -> Self {
		Self {
			value: ComparableValue(value),
			derived: Vec::new(),
			value_type: PhantomData,
		}
	}
}

impl<T> Observed<T, NonComparableValue<T>> {
	pub(crate) fn new(value: T) -> Self {
		Self {
			value: NonComparableValue(value),
			derived: Vec::new(),
			value_type: PhantomData,
		}
	}
}

pub struct Computed<T, V: Value<T>, F: Fn(&mut Connect) -> T> {
	comp_fun: F,
	value: V,
	derived: Vec<WeakDynComputedNode>,
	dependencies: Vec<ConnectNode>,
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T> Drop for Computed<T, V, F> {
	fn drop(&mut self) {
		for dependency in self.get_dependencies() {
			match dependency {
				ConnectNode::Observed(dependency)
				| ConnectNode::ObservedAny(dependency) => dependency
					.borrow_mut()
					.get_mut_derived()
					.retain(|derived| derived.strong_count() > 0),
				ConnectNode::Computed(dependency)
				| ConnectNode::ComputedAny(dependency)
				| ConnectNode::Effected(dependency)
				| ConnectNode::EffectedAny(dependency) => dependency
					.borrow_mut()
					.get_mut_derived()
					.retain(|derived| derived.strong_count() > 0),
			}
		}
	}
}

impl<T: PartialEq, F: Fn(&mut Connect) -> T> Computed<T, ComparableValue<T>, F> {
	pub(crate) fn new(comp_fun: F, value: T, dependencies: Vec<ConnectNode>) -> Self {
		Self {
			value: ComparableValue(value),
			comp_fun,
			derived: Vec::new(),
			dependencies,
		}
	}
}

impl<T, F: Fn(&mut Connect) -> T> Computed<T, NonComparableValue<T>, F> {
	pub(crate) fn new(comp_fun: F, value: T, dependencies: Vec<ConnectNode>) -> Self {
		Self {
			value: NonComparableValue(value),
			comp_fun,
			derived: Vec::new(),
			dependencies,
		}
	}
}

pub struct Effected<T, V: Value<T>, F: Fn(&mut Connect) -> T, E: FnMut(&T)> {
	comp_fun: F,
	value: V,
	effect: E,
	derived: Vec<WeakDynComputedNode>,
	dependencies: Vec<ConnectNode>,
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T, E: FnMut(&T)> Drop
	for Effected<T, V, F, E>
{
	fn drop(&mut self) {
		for dependency in self.get_dependencies() {
			match dependency {
				ConnectNode::Observed(dependency)
				| ConnectNode::ObservedAny(dependency) => dependency
					.borrow_mut()
					.get_mut_derived()
					.retain(|derived| derived.strong_count() > 0),
				ConnectNode::Computed(dependency)
				| ConnectNode::ComputedAny(dependency)
				| ConnectNode::Effected(dependency)
				| ConnectNode::EffectedAny(dependency) => dependency
					.borrow_mut()
					.get_mut_derived()
					.retain(|derived| derived.strong_count() > 0),
			}
		}
	}
}

impl<T: PartialEq, F: Fn(&mut Connect) -> T, E: FnMut(&T)>
	Effected<T, ComparableValue<T>, F, E>
{
	pub(crate) fn new(
		comp_fun: F,
		value: T,
		effect: E,
		dependencies: Vec<ConnectNode>,
	) -> Self {
		Self {
			value: ComparableValue(value),
			comp_fun,
			effect,
			derived: Vec::new(),
			dependencies,
		}
	}
}

impl<T, F: Fn(&mut Connect) -> T, E: FnMut(&T)> Effected<T, NonComparableValue<T>, F, E> {
	pub(crate) fn new(
		comp_fun: F,
		value: T,
		effect: E,
		dependencies: Vec<ConnectNode>,
	) -> Self {
		Self {
			value: NonComparableValue(value),
			comp_fun,
			effect,
			derived: Vec::new(),
			dependencies,
		}
	}
}

impl<T, V: Value<T>> Node for Observed<T, V> {
	fn get_derived(&self) -> &Vec<WeakDynComputedNode> {
		&self.derived
	}

	fn get_mut_derived(&mut self) -> &mut Vec<WeakDynComputedNode> {
		&mut self.derived
	}
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T> Node for Computed<T, V, F> {
	fn get_derived(&self) -> &Vec<WeakDynComputedNode> {
		&self.derived
	}

	fn get_mut_derived(&mut self) -> &mut Vec<WeakDynComputedNode> {
		&mut self.derived
	}
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T> ComputedNode for Computed<T, V, F> {
	fn get_dependencies(&self) -> &Vec<ConnectNode> {
		&self.dependencies
	}

	fn recalculate(&mut self, c: &mut Connect) -> bool {
		let value = self.value.set_own((self.comp_fun)(c));
		!self.value.equal(&value)
	}

	fn set_dependencies(&mut self, dependencies: Vec<ConnectNode>) {
		self.dependencies = dependencies;
	}

	fn run_effect(&mut self) {}
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T, E: FnMut(&T)> Node
	for Effected<T, V, F, E>
{
	fn get_derived(&self) -> &Vec<WeakDynComputedNode> {
		&self.derived
	}

	fn get_mut_derived(&mut self) -> &mut Vec<WeakDynComputedNode> {
		&mut self.derived
	}
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T, E: FnMut(&T)> ComputedNode
	for Effected<T, V, F, E>
{
	fn get_dependencies(&self) -> &Vec<ConnectNode> {
		&self.dependencies
	}

	fn recalculate(&mut self, c: &mut Connect) -> bool {
		let value = self.value.set_own((self.comp_fun)(c));
		!self.value.equal(&value)
	}

	fn set_dependencies(&mut self, dependencies: Vec<ConnectNode>) {
		self.dependencies = dependencies;
	}

	fn run_effect(&mut self) {
		(self.effect)(self.value.get_ref())
	}
}

impl<T, V: Value<T>> NodeValueAccess for Rc<RefCell<Observed<T, V>>> {
	type Value = T;
	type CompFun = ();

	fn get_inert(&self) -> Ref<T> {
		Ref::map(self.borrow(), |observed| observed.value.get_ref())
	}

	fn set_inert(&self, value: T) -> T {
		self.borrow_mut().value.set_own(value)
	}

	fn equal(&self, value: &T) -> bool {
		self.borrow().value.equal(value)
	}
}

impl<T, V: Value<T>, F: Fn(&mut Connect) -> T> NodeValueAccess
	for Rc<RefCell<Computed<T, V, F>>>
{
	type Value = T;
	type CompFun = F;

	fn get_inert(&self) -> Ref<T> {
		Ref::map(self.borrow(), |observed| observed.value.get_ref())
	}

	fn set_inert(&self, value: T) -> T {
		self.borrow_mut().value.set_own(value)
	}

	fn equal(&self, _value: &T) -> bool {
		false
	}
}

impl<T: PartialEq + 'static> From<ConnectObserved<T>> for ConnectNode {
	fn from(node: ConnectObserved<T>) -> ConnectNode {
		ConnectNode::Observed(node as DynNode)
	}
}

impl<T: 'static> From<ConnectObservedAny<T>> for ConnectNode {
	fn from(node: ConnectObservedAny<T>) -> ConnectNode {
		ConnectNode::ObservedAny(node as DynNode)
	}
}

impl<T: PartialEq + 'static, F: Fn(&mut Connect) -> T + 'static>
	From<ConnectComputed<T, F>> for ConnectNode
{
	fn from(node: ConnectComputed<T, F>) -> ConnectNode {
		ConnectNode::Computed(node as DynComputedNode)
	}
}

impl<T: 'static, F: Fn(&mut Connect) -> T + 'static> From<ConnectComputedAny<T, F>>
	for ConnectNode
{
	fn from(node: ConnectComputedAny<T, F>) -> ConnectNode {
		ConnectNode::ComputedAny(node as DynComputedNode)
	}
}