rsconnect 0.2.2

Fine-grained reactivity in Rust
Documentation
use std::cell::Ref;

use crate::{
	connect_node_update::NodeUpdate,
	connect_structs::Connect,
	connect_update::ConnectUpdate,
	node_traits::{AnyDynNode, ConnectNode, NodeValueAccess},
};

pub(crate) trait ConnectNodeUpdateInitiator {
	fn before_get_node(&mut self, node: ConnectNode);

	fn after_set_node(&mut self, node: ConnectNode);

	fn after_set_nodes(&mut self, modified_nodes: Vec<AnyDynNode>);
}

impl ConnectNodeUpdateInitiator for Connect {
	fn before_get_node<'a>(&mut self, node: ConnectNode) {
		self.add_to_current_update_dependencies(&node);
	}

	fn after_set_node<'a>(&mut self, node: ConnectNode) {
		match &mut self.modified_nodes {
			None => {
				self.after_set_nodes(vec![node.into()]);
			}
			Some(modified_nodes) => {
				modified_nodes.push(node.into());
			}
		}
	}

	fn after_set_nodes(&mut self, mut modified_nodes: Vec<AnyDynNode>) {
		let update_list = self.get_update_list(&mut modified_nodes);
		self.recalculate_update_list(&mut modified_nodes, update_list);
	}
}

trait ConnectNodeAccess {
	fn get_concrete_from_node<'a, N: ?Sized, R>(&self, node: &N) -> &'a R;

	fn get_mut_concrete_from_node<'a, N: ?Sized, R>(&self, node: &mut N) -> &'a mut R;
}

impl ConnectNodeAccess for Connect {
	fn get_concrete_from_node<'a, N: ?Sized, R>(&self, node: &N) -> &'a R {
		let node_dyn_ptr: *const N = node;
		let node_ptr = node_dyn_ptr.cast::<R>();
		unsafe {
			if let Some(node_ref) = node_ptr.as_ref() {
				node_ref
			} else {
				unreachable!()
			}
		}
	}

	fn get_mut_concrete_from_node<'a, N: ?Sized, R>(&self, node: &mut N) -> &'a mut R {
		let node_dyn_ptr: *mut N = node;
		let node_ptr = node_dyn_ptr.cast::<R>();
		unsafe {
			if let Some(node_mut) = node_ptr.as_mut() {
				node_mut
			} else {
				unreachable!()
			}
		}
	}
}

pub trait ConnectNodeInterface {
	fn get<'a, T: NodeValueAccess + Into<ConnectNode> + Clone + 'static>(
		&mut self,
		node: &'a T,
	) -> Ref<'a, T::Value>;

	fn set<T: NodeValueAccess + Into<ConnectNode> + Clone + 'static>(
		&mut self,
		node: &'_ T,
		value: T::Value,
	) -> T::Value;
}

impl ConnectNodeInterface for Connect {
	fn get<'a, T: NodeValueAccess + Into<ConnectNode> + Clone + 'static>(
		&mut self,
		node: &'a T,
	) -> Ref<'a, T::Value> {
		self.before_get_node(node.clone().into());
		node.get_inert()
	}

	fn set<T: NodeValueAccess + Into<ConnectNode> + Clone + 'static>(
		&mut self,
		node: &'_ T,
		value: T::Value,
	) -> T::Value {
		let prev_value = node.set_inert(value);
		let is_changed = !node.equal(&prev_value);
		if is_changed {
			self.after_set_node(node.clone().into());
		}
		prev_value
	}
}