1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063 |
- //! A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
- use rustc_hash::{FxHashMap, FxHashSet};
- use shipyard::error::GetStorage;
- use shipyard::track::Untracked;
- use shipyard::{Component, Get, IntoBorrow, ScheduledWorkload, Unique, View, ViewMut, Workload};
- use shipyard::{SystemModificator, World};
- use std::any::TypeId;
- use std::collections::VecDeque;
- use std::ops::{Deref, DerefMut};
- use std::sync::{Arc, RwLock};
- use crate::node::{
- ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, TextNode,
- };
- use crate::node_ref::{NodeMask, NodeMaskBuilder};
- use crate::node_watcher::NodeWatcher;
- use crate::passes::{DirtyNodeStates, PassDirection, TypeErasedState};
- use crate::prelude::AttributeMaskBuilder;
- use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView};
- use crate::NodeId;
- use crate::{FxDashSet, SendAnyMap};
- /// The context passes can receive when they are executed
- #[derive(Unique)]
- pub(crate) struct SendAnyMapWrapper(SendAnyMap);
- impl Deref for SendAnyMapWrapper {
- type Target = SendAnyMap;
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
- /// The nodes that were changed when updating the state of the RealDom
- #[derive(Unique, Default)]
- pub(crate) struct DirtyNodesResult(FxDashSet<NodeId>);
- impl Deref for DirtyNodesResult {
- type Target = FxDashSet<NodeId>;
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
- /// The nodes that have been marked as dirty in the RealDom
- pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
- passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
- nodes_updated: FxHashMap<NodeId, NodeMask>,
- pub(crate) passes: Box<[TypeErasedState<V>]>,
- }
- impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
- /// Mark a node as dirty
- fn mark_dirty(&mut self, node_id: NodeId, mask: NodeMask) {
- self.passes_updated.entry(node_id).or_default().extend(
- self.passes
- .iter()
- .filter_map(|x| x.mask.overlaps(&mask).then_some(x.this_type_id)),
- );
- let nodes_updated = &mut self.nodes_updated;
- if let Some(node) = nodes_updated.get_mut(&node_id) {
- *node = node.union(&mask);
- } else {
- nodes_updated.insert(node_id, mask);
- }
- }
- /// Mark a node that has had a parent changed
- fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
- let hm = self.passes_updated.entry(node_id).or_default();
- for pass in &*self.passes {
- // If any of the states in this node depend on the parent then mark them as dirty
- for &pass in &pass.parent_dependancies_ids {
- hm.insert(pass);
- }
- }
- }
- /// Mark a node as having a child added or removed
- fn mark_child_changed(&mut self, node_id: NodeId) {
- let hm = self.passes_updated.entry(node_id).or_default();
- for pass in &*self.passes {
- // If any of the states in this node depend on the children then mark them as dirty
- for &pass in &pass.child_dependancies_ids {
- hm.insert(pass);
- }
- }
- }
- }
- type NodeWatchers<V> = Arc<RwLock<Vec<Box<dyn NodeWatcher<V> + Send + Sync>>>>;
- /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
- /// The render state passes from parent to children and or accumulates state from children to parents.
- /// To get started:
- /// 1) Implement [crate::passes::State] for each part of your state that you want to compute incrementally
- /// 2) Create a RealDom [RealDom::new], passing in each state you created
- /// 3) Update the state of the RealDom by adding and modifying nodes
- /// 4) Call [RealDom::update_state] to update the state of incrementally computed values on each node
- ///
- /// # Custom attribute values
- /// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
- pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
- pub(crate) world: World,
- nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
- pub(crate) dirty_nodes: NodesDirty<V>,
- node_watchers: NodeWatchers<V>,
- workload: ScheduledWorkload,
- root_id: NodeId,
- phantom: std::marker::PhantomData<V>,
- }
- impl<V: FromAnyValue + Send + Sync> RealDom<V> {
- /// Create a new RealDom with the given states that will be inserted and updated when needed
- pub fn new(tracked_states: impl Into<Box<[TypeErasedState<V>]>>) -> RealDom<V> {
- let mut tracked_states = tracked_states.into();
- // resolve dependants for each pass
- for i in 1..=tracked_states.len() {
- let (before, after) = tracked_states.split_at_mut(i);
- let (current, before) = before.split_last_mut().unwrap();
- for state in before.iter_mut().chain(after.iter_mut()) {
- let dependants = Arc::get_mut(&mut state.dependants).unwrap();
- // If this node depends on the other state as a parent, then the other state should update its children of the current type when it is invalidated
- if current
- .parent_dependancies_ids
- .contains(&state.this_type_id)
- && !dependants.child.contains(¤t.this_type_id)
- {
- dependants.child.push(current.this_type_id);
- }
- // If this node depends on the other state as a child, then the other state should update its parent of the current type when it is invalidated
- if current.child_dependancies_ids.contains(&state.this_type_id)
- && !dependants.parent.contains(¤t.this_type_id)
- {
- dependants.parent.push(current.this_type_id);
- }
- // If this node depends on the other state as a sibling, then the other state should update its siblings of the current type when it is invalidated
- if current.node_dependancies_ids.contains(&state.this_type_id)
- && !dependants.node.contains(¤t.this_type_id)
- {
- dependants.node.push(current.this_type_id);
- }
- }
- // If the current state depends on itself, then it should update itself when it is invalidated
- let dependants = Arc::get_mut(&mut current.dependants).unwrap();
- match current.pass_direction {
- PassDirection::ChildToParent => {
- if !dependants.parent.contains(¤t.this_type_id) {
- dependants.parent.push(current.this_type_id);
- }
- }
- PassDirection::ParentToChild => {
- if !dependants.child.contains(¤t.this_type_id) {
- dependants.child.push(current.this_type_id);
- }
- }
- _ => {}
- }
- }
- let workload = construct_workload(&mut tracked_states);
- let (workload, _) = workload.build().unwrap();
- let mut world = World::new();
- let root_node: NodeType<V> = NodeType::Element(ElementNode {
- tag: "Root".to_string(),
- namespace: Some("Root".to_string()),
- attributes: FxHashMap::default(),
- listeners: FxHashSet::default(),
- });
- let root_id = world.add_entity(root_node);
- {
- let mut tree: TreeMutView = world.borrow().unwrap();
- tree.create_node(root_id);
- }
- let mut passes_updated = FxHashMap::default();
- let mut nodes_updated = FxHashMap::default();
- passes_updated.insert(
- root_id,
- tracked_states.iter().map(|x| x.this_type_id).collect(),
- );
- nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
- RealDom {
- world,
- nodes_listening: FxHashMap::default(),
- dirty_nodes: NodesDirty {
- passes_updated,
- nodes_updated,
- passes: tracked_states,
- },
- node_watchers: Default::default(),
- workload,
- root_id,
- phantom: std::marker::PhantomData,
- }
- }
- /// Get a reference to the tree.
- pub fn tree_ref(&self) -> TreeRefView {
- self.world.borrow().unwrap()
- }
- /// Get a mutable reference to the tree.
- pub fn tree_mut(&self) -> TreeMutView {
- self.world.borrow().unwrap()
- }
- /// Create a new node of the given type in the dom and return a mutable reference to it.
- pub fn create_node(&mut self, node: impl Into<NodeType<V>>) -> NodeMut<'_, V> {
- let id = self.world.add_entity(node.into());
- self.tree_mut().create_node(id);
- self.dirty_nodes
- .passes_updated
- .entry(id)
- .or_default()
- .extend(self.dirty_nodes.passes.iter().map(|x| x.this_type_id));
- self.dirty_nodes
- .mark_dirty(id, NodeMaskBuilder::ALL.build());
- let watchers = self.node_watchers.clone();
- for watcher in &*watchers.read().unwrap() {
- watcher.on_node_added(NodeMut::new(id, self));
- }
- NodeMut::new(id, self)
- }
- /// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
- /// This can be useful to avoid creating duplicate events.
- pub fn get_listening_sorted(&self, event: &str) -> Vec<NodeRef<V>> {
- if let Some(nodes) = self.nodes_listening.get(event) {
- let mut listening: Vec<_> = nodes
- .iter()
- .map(|id| (*id, self.tree_ref().height(*id).unwrap()))
- .collect();
- listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
- listening
- .into_iter()
- .map(|(id, _)| NodeRef { id, dom: self })
- .collect()
- } else {
- Vec::new()
- }
- }
- /// Returns the id of the root node.
- pub fn root_id(&self) -> NodeId {
- self.root_id
- }
- /// Check if a node exists in the dom.
- pub fn contains(&self, id: NodeId) -> bool {
- self.tree_ref().contains(id)
- }
- /// Get a reference to a node.
- pub fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
- self.contains(id).then_some(NodeRef { id, dom: self })
- }
- /// Get a mutable reference to a node.
- pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
- let contains = self.contains(id);
- contains.then(|| NodeMut::new(id, self))
- }
- /// Borrow a component from the world without updating the dirty nodes.
- fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result<B, GetStorage>
- where
- B::Borrow: shipyard::Borrow<'a, View = B>,
- {
- self.world.borrow()
- }
- /// Borrow a component from the world without updating the dirty nodes.
- fn borrow_node_type_mut(&self) -> Result<ViewMut<NodeType<V>>, GetStorage> {
- self.world.borrow()
- }
- /// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
- pub fn update_state(
- &mut self,
- ctx: SendAnyMap,
- ) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
- let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
- let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
- let dirty_nodes =
- DirtyNodeStates::with_passes(self.dirty_nodes.passes.iter().map(|p| p.this_type_id));
- let tree = self.tree_ref();
- for (node_id, passes) in passes {
- // remove any nodes that were created and then removed in the same mutations from the dirty nodes list
- if let Some(height) = tree.height(node_id) {
- for pass in passes {
- dirty_nodes.insert(pass, node_id, height);
- }
- }
- }
- let _ = self.world.remove_unique::<DirtyNodeStates>();
- let _ = self.world.remove_unique::<SendAnyMapWrapper>();
- self.world.add_unique(dirty_nodes);
- self.world.add_unique(SendAnyMapWrapper(ctx));
- self.world.add_unique(DirtyNodesResult::default());
- self.workload.run_with_world(&self.world).unwrap();
- let dirty = self.world.remove_unique::<DirtyNodesResult>().unwrap();
- (dirty.0, nodes_updated)
- }
- /// Traverses the dom in a depth first manner, calling the provided function on each node.
- pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
- let mut stack = vec![self.root_id()];
- let tree = self.tree_ref();
- while let Some(id) = stack.pop() {
- if let Some(node) = self.get(id) {
- f(node);
- let children = tree.children_ids(id);
- stack.extend(children.iter().copied().rev());
- }
- }
- }
- /// Traverses the dom in a breadth first manner, calling the provided function on each node.
- pub fn traverse_breadth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
- let mut queue = VecDeque::new();
- queue.push_back(self.root_id());
- let tree = self.tree_ref();
- while let Some(id) = queue.pop_front() {
- if let Some(node) = self.get(id) {
- f(node);
- let children = tree.children_ids(id);
- for id in children {
- queue.push_back(id);
- }
- }
- }
- }
- /// Traverses the dom in a depth first manner mutably, calling the provided function on each node.
- pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(NodeMut<V>)) {
- let mut stack = vec![self.root_id()];
- while let Some(id) = stack.pop() {
- let tree = self.tree_ref();
- let mut children = tree.children_ids(id);
- drop(tree);
- children.reverse();
- if let Some(node) = self.get_mut(id) {
- let node = node;
- f(node);
- stack.extend(children.iter());
- }
- }
- }
- /// Traverses the dom in a breadth first manner mutably, calling the provided function on each node.
- pub fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(NodeMut<V>)) {
- let mut queue = VecDeque::new();
- queue.push_back(self.root_id());
- while let Some(id) = queue.pop_front() {
- let tree = self.tree_ref();
- let children = tree.children_ids(id);
- drop(tree);
- if let Some(node) = self.get_mut(id) {
- f(node);
- for id in children {
- queue.push_back(id);
- }
- }
- }
- }
- /// Adds a [`NodeWatcher`] to the dom. Node watchers are called whenever a node is created or removed.
- pub fn add_node_watcher(&mut self, watcher: impl NodeWatcher<V> + 'static + Send + Sync) {
- self.node_watchers.write().unwrap().push(Box::new(watcher));
- }
- /// Returns a reference to the underlying world. Any changes made to the world will not update the reactive system.
- pub fn raw_world(&self) -> &World {
- &self.world
- }
- /// Returns a mutable reference to the underlying world. Any changes made to the world will not update the reactive system.
- pub fn raw_world_mut(&mut self) -> &mut World {
- &mut self.world
- }
- }
- /// A reference to a tracked component in a node.
- pub struct ViewEntry<'a, V: Component + Send + Sync> {
- view: View<'a, V>,
- id: NodeId,
- }
- impl<'a, V: Component + Send + Sync> ViewEntry<'a, V> {
- fn new(view: View<'a, V>, id: NodeId) -> Self {
- Self { view, id }
- }
- }
- impl<'a, V: Component + Send + Sync> Deref for ViewEntry<'a, V> {
- type Target = V;
- fn deref(&self) -> &Self::Target {
- &self.view[self.id]
- }
- }
- /// A mutable reference to a tracked component in a node.
- pub struct ViewEntryMut<'a, V: Component<Tracking = Untracked> + Send + Sync> {
- view: ViewMut<'a, V, Untracked>,
- id: NodeId,
- }
- impl<'a, V: Component<Tracking = Untracked> + Send + Sync> ViewEntryMut<'a, V> {
- fn new(view: ViewMut<'a, V, Untracked>, id: NodeId) -> Self {
- Self { view, id }
- }
- }
- impl<'a, V: Component<Tracking = Untracked> + Send + Sync> Deref for ViewEntryMut<'a, V> {
- type Target = V;
- fn deref(&self) -> &Self::Target {
- self.view.get(self.id).unwrap()
- }
- }
- impl<'a, V: Component<Tracking = Untracked> + Send + Sync> DerefMut for ViewEntryMut<'a, V> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- (&mut self.view).get(self.id).unwrap()
- }
- }
- /// A immutable view of a node
- pub trait NodeImmutable<V: FromAnyValue + Send + Sync = ()>: Sized {
- /// Get the real dom this node was created in
- fn real_dom(&self) -> &RealDom<V>;
- /// Get the id of the current node
- fn id(&self) -> NodeId;
- /// Get the type of the current node
- #[inline]
- fn node_type(&self) -> ViewEntry<NodeType<V>> {
- self.get().unwrap()
- }
- /// Get a component from the current node
- #[inline]
- fn get<'a, T: Component + Sync + Send>(&'a self) -> Option<ViewEntry<'a, T>> {
- // self.real_dom().tree.get(self.id())
- let view: View<'a, T> = self.real_dom().borrow_raw().ok()?;
- view.contains(self.id())
- .then(|| ViewEntry::new(view, self.id()))
- }
- /// Get the ids of the children of the current node
- #[inline]
- fn child_ids(&self) -> Vec<NodeId> {
- self.real_dom().tree_ref().children_ids(self.id())
- }
- /// Get the children of the current node
- #[inline]
- fn children(&self) -> Vec<NodeRef<V>> {
- self.child_ids()
- .iter()
- .map(|id| NodeRef {
- id: *id,
- dom: self.real_dom(),
- })
- .collect()
- }
- /// Get the id of the parent of the current node
- #[inline]
- fn parent_id(&self) -> Option<NodeId> {
- self.real_dom().tree_ref().parent_id(self.id())
- }
- /// Get the parent of the current node
- #[inline]
- fn parent(&self) -> Option<NodeRef<V>> {
- self.parent_id().map(|id| NodeRef {
- id,
- dom: self.real_dom(),
- })
- }
- /// Get the node after the current node
- #[inline]
- fn next(&self) -> Option<NodeRef<V>> {
- let parent = self.parent_id()?;
- let children = self.real_dom().tree_ref().children_ids(parent);
- let index = children.iter().position(|id| *id == self.id())?;
- if index + 1 < children.len() {
- Some(NodeRef {
- id: children[index + 1],
- dom: self.real_dom(),
- })
- } else {
- None
- }
- }
- /// Get the node before the current node
- #[inline]
- fn prev(&self) -> Option<NodeRef<V>> {
- let parent = self.parent_id()?;
- let children = self.real_dom().tree_ref().children_ids(parent);
- let index = children.iter().position(|id| *id == self.id())?;
- if index > 0 {
- Some(NodeRef {
- id: children[index - 1],
- dom: self.real_dom(),
- })
- } else {
- None
- }
- }
- /// Get the height of the current node in the tree (the number of nodes between the current node and the root)
- #[inline]
- fn height(&self) -> u16 {
- self.real_dom().tree_ref().height(self.id()).unwrap()
- }
- }
- /// An immutable reference to a node in a RealDom
- pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
- id: NodeId,
- dom: &'a RealDom<V>,
- }
- impl<'a, V: FromAnyValue + Send + Sync> Clone for NodeRef<'a, V> {
- fn clone(&self) -> Self {
- Self {
- id: self.id,
- dom: self.dom,
- }
- }
- }
- impl<'a, V: FromAnyValue + Send + Sync> Copy for NodeRef<'a, V> {}
- impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'a, V> {
- #[inline(always)]
- fn real_dom(&self) -> &RealDom<V> {
- self.dom
- }
- #[inline(always)]
- fn id(&self) -> NodeId {
- self.id
- }
- }
- /// A mutable refrence to a node in the RealDom that tracks what States need to be updated
- pub struct NodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
- id: NodeId,
- dom: &'a mut RealDom<V>,
- }
- impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
- /// Create a new mutable refrence to a node in a RealDom
- pub fn new(id: NodeId, dom: &'a mut RealDom<V>) -> Self {
- Self { id, dom }
- }
- }
- impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMut<'a, V> {
- #[inline(always)]
- fn real_dom(&self) -> &RealDom<V> {
- self.dom
- }
- #[inline(always)]
- fn id(&self) -> NodeId {
- self.id
- }
- }
- impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
- /// Get the real dom this node was created in mutably
- #[inline(always)]
- pub fn real_dom_mut(&mut self) -> &mut RealDom<V> {
- self.dom
- }
- /// Get the parent of this node mutably
- #[inline]
- pub fn parent_mut(&mut self) -> Option<NodeMut<V>> {
- self.parent_id().map(|id| NodeMut { id, dom: self.dom })
- }
- /// Get a component from the current node mutably
- #[inline]
- pub fn get_mut<T: Component<Tracking = Untracked> + Sync + Send>(
- &mut self,
- ) -> Option<ViewEntryMut<T>> {
- // mark the node state as dirty
- self.dom
- .dirty_nodes
- .passes_updated
- .entry(self.id)
- .or_default()
- .insert(TypeId::of::<T>());
- let view_mut: ViewMut<T> = self.dom.borrow_raw().ok()?;
- view_mut
- .contains(self.id)
- .then_some(ViewEntryMut::new(view_mut, self.id))
- }
- /// Insert a custom component into this node
- ///
- /// Note: Components that implement State and are added when the RealDom is created will automatically be created
- #[inline]
- pub fn insert<T: Component + Sync + Send>(&mut self, value: T) {
- // mark the node state as dirty
- self.dom
- .dirty_nodes
- .passes_updated
- .entry(self.id)
- .or_default()
- .insert(TypeId::of::<T>());
- self.dom.world.add_component(self.id, value);
- }
- /// Get the next node
- #[inline]
- pub fn next_mut(self) -> Option<NodeMut<'a, V>> {
- let parent = self.parent_id()?;
- let children = self.dom.tree_mut().children_ids(parent);
- let index = children.iter().position(|id| *id == self.id)?;
- if index + 1 < children.len() {
- Some(NodeMut::new(children[index + 1], self.dom))
- } else {
- None
- }
- }
- /// Get the previous node
- #[inline]
- pub fn prev_mut(self) -> Option<NodeMut<'a, V>> {
- let parent = self.parent_id()?;
- let children = self.dom.tree_ref().children_ids(parent);
- let index = children.iter().position(|id| *id == self.id)?;
- if index > 0 {
- Some(NodeMut::new(children[index - 1], self.dom))
- } else {
- None
- }
- }
- /// Add the given node to the end of this nodes children
- #[inline]
- pub fn add_child(&mut self, child: NodeId) {
- self.dom.dirty_nodes.mark_child_changed(self.id);
- self.dom.dirty_nodes.mark_parent_added_or_removed(child);
- self.dom.tree_mut().add_child(self.id, child);
- NodeMut::new(child, self.dom).mark_moved();
- }
- /// Insert this node after the given node
- #[inline]
- pub fn insert_after(&mut self, old: NodeId) {
- let id = self.id();
- let parent_id = { self.dom.tree_ref().parent_id(old) };
- if let Some(parent_id) = parent_id {
- self.dom.dirty_nodes.mark_child_changed(parent_id);
- self.dom.dirty_nodes.mark_parent_added_or_removed(id);
- }
- self.dom.tree_mut().insert_after(old, id);
- self.mark_moved();
- }
- /// Insert this node before the given node
- #[inline]
- pub fn insert_before(&mut self, old: NodeId) {
- let id = self.id();
- let parent_id = { self.dom.tree_ref().parent_id(old) };
- if let Some(parent_id) = parent_id {
- self.dom.dirty_nodes.mark_child_changed(parent_id);
- self.dom.dirty_nodes.mark_parent_added_or_removed(id);
- }
- self.dom.tree_mut().insert_before(old, id);
- self.mark_moved();
- }
- /// Remove this node from the RealDom
- #[inline]
- pub fn remove(&mut self) {
- let id = self.id();
- {
- let RealDom {
- world,
- nodes_listening,
- ..
- } = &mut self.dom;
- let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
- if let NodeType::Element(ElementNode { listeners, .. })
- | NodeType::Text(TextNode { listeners, .. }) = (&mut view).get(id).unwrap()
- {
- let listeners = std::mem::take(listeners);
- for event in listeners {
- nodes_listening.get_mut(&event).unwrap().remove(&id);
- }
- }
- }
- self.mark_removed();
- let parent_id = { self.dom.tree_ref().parent_id(id) };
- if let Some(parent_id) = parent_id {
- self.real_dom_mut()
- .dirty_nodes
- .mark_child_changed(parent_id);
- }
- let children_ids = self.child_ids();
- let children_ids_vec = children_ids.to_vec();
- for child in children_ids_vec {
- self.dom.get_mut(child).unwrap().remove();
- }
- self.dom.tree_mut().remove(id);
- self.real_dom_mut().raw_world_mut().delete_entity(id);
- }
- /// Replace this node with a different node
- #[inline]
- pub fn replace(mut self, new: NodeId) {
- self.mark_removed();
- if let Some(parent_id) = self.parent_id() {
- self.real_dom_mut()
- .dirty_nodes
- .mark_child_changed(parent_id);
- self.real_dom_mut()
- .dirty_nodes
- .mark_parent_added_or_removed(new);
- }
- let id = self.id();
- self.dom.tree_mut().replace(id, new);
- }
- /// Add an event listener
- #[inline]
- pub fn add_event_listener(&mut self, event: &str) {
- let id = self.id();
- let RealDom {
- world,
- dirty_nodes,
- nodes_listening,
- ..
- } = &mut self.dom;
- let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
- let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
- if let NodeType::Element(ElementNode { listeners, .. })
- | NodeType::Text(TextNode { listeners, .. }) = node_type
- {
- dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
- listeners.insert(event.to_string());
- match nodes_listening.get_mut(event) {
- Some(hs) => {
- hs.insert(id);
- }
- None => {
- let mut hs = FxHashSet::default();
- hs.insert(id);
- nodes_listening.insert(event.to_string(), hs);
- }
- }
- }
- }
- /// Remove an event listener
- #[inline]
- pub fn remove_event_listener(&mut self, event: &str) {
- let id = self.id();
- let RealDom {
- world,
- dirty_nodes,
- nodes_listening,
- ..
- } = &mut self.dom;
- let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
- let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
- if let NodeType::Element(ElementNode { listeners, .. })
- | NodeType::Text(TextNode { listeners, .. }) = node_type
- {
- dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
- listeners.remove(event);
- nodes_listening.get_mut(event).unwrap().remove(&id);
- }
- }
- /// mark that this node was removed for the incremental system
- fn mark_removed(&mut self) {
- let watchers = self.dom.node_watchers.clone();
- for watcher in &*watchers.read().unwrap() {
- watcher.on_node_removed(NodeMut::new(self.id(), self.dom));
- }
- }
- /// mark that this node was moved for the incremental system
- fn mark_moved(&mut self) {
- let watchers = self.dom.node_watchers.clone();
- for watcher in &*watchers.read().unwrap() {
- watcher.on_node_moved(NodeMut::new(self.id(), self.dom));
- }
- }
- /// Get a mutable reference to the type of the current node
- pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
- let id = self.id();
- let RealDom {
- world, dirty_nodes, ..
- } = &mut self.dom;
- let view: ViewMut<NodeType<V>> = world.borrow().unwrap();
- let node_type = ViewEntryMut::new(view, id);
- match &*node_type {
- NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut {
- id,
- element: node_type,
- dirty_nodes,
- }),
- NodeType::Text(_) => NodeTypeMut::Text(TextNodeMut {
- id,
- text: node_type,
- dirty_nodes,
- }),
- NodeType::Placeholder => NodeTypeMut::Placeholder,
- }
- }
- /// Set the type of the current node
- pub fn set_type(&mut self, new: NodeType<V>) {
- {
- let mut view: ViewMut<NodeType<V>> = self.dom.borrow_node_type_mut().unwrap();
- *(&mut view).get(self.id).unwrap() = new;
- }
- self.dom
- .dirty_nodes
- .mark_dirty(self.id, NodeMaskBuilder::ALL.build())
- }
- /// Clone a node and it's children and returns the id of the new node.
- /// This is more effecient than creating the node from scratch because it can pre-allocate the memory required.
- #[inline]
- pub fn clone_node(&mut self) -> NodeId {
- let new_node = self.node_type().clone();
- let rdom = self.real_dom_mut();
- let new_id = rdom.create_node(new_node).id();
- let children = self.child_ids();
- let children = children.to_vec();
- let rdom = self.real_dom_mut();
- for child in children {
- let child_id = rdom.get_mut(child).unwrap().clone_node();
- rdom.get_mut(new_id).unwrap().add_child(child_id);
- }
- new_id
- }
- }
- /// A mutable refrence to the type of a node in the RealDom
- pub enum NodeTypeMut<'a, V: FromAnyValue + Send + Sync = ()> {
- /// An element node
- Element(ElementNodeMut<'a, V>),
- /// A text node
- Text(TextNodeMut<'a, V>),
- /// A placeholder node
- Placeholder,
- }
- /// A mutable refrence to a text node in the RealDom
- pub struct TextNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
- id: NodeId,
- text: ViewEntryMut<'a, NodeType<V>>,
- dirty_nodes: &'a mut NodesDirty<V>,
- }
- impl<V: FromAnyValue + Send + Sync> TextNodeMut<'_, V> {
- /// Get the underlying test of the node
- pub fn text(&self) -> &str {
- match &*self.text {
- NodeType::Text(text) => &text.text,
- _ => unreachable!(),
- }
- }
- /// Get the underlying text mutably
- pub fn text_mut(&mut self) -> &mut String {
- self.dirty_nodes
- .mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
- match &mut *self.text {
- NodeType::Text(text) => &mut text.text,
- _ => unreachable!(),
- }
- }
- }
- impl<V: FromAnyValue + Send + Sync> Deref for TextNodeMut<'_, V> {
- type Target = String;
- fn deref(&self) -> &Self::Target {
- match &*self.text {
- NodeType::Text(text) => &text.text,
- _ => unreachable!(),
- }
- }
- }
- impl<V: FromAnyValue + Send + Sync> DerefMut for TextNodeMut<'_, V> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.text_mut()
- }
- }
- /// A mutable refrence to a text Element node in the RealDom
- pub struct ElementNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
- id: NodeId,
- element: ViewEntryMut<'a, NodeType<V>>,
- dirty_nodes: &'a mut NodesDirty<V>,
- }
- impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
- /// Get the current element
- fn element(&self) -> &ElementNode<V> {
- match &*self.element {
- NodeType::Element(element) => element,
- _ => unreachable!(),
- }
- }
- /// Get the current element mutably (does not mark anything as dirty)
- fn element_mut(&mut self) -> &mut ElementNode<V> {
- match &mut *self.element {
- NodeType::Element(element) => element,
- _ => unreachable!(),
- }
- }
- /// Get the tag of the element
- pub fn tag(&self) -> &str {
- &self.element().tag
- }
- /// Get a mutable reference to the tag of the element
- pub fn tag_mut(&mut self) -> &mut String {
- self.dirty_nodes
- .mark_dirty(self.id, NodeMaskBuilder::new().with_tag().build());
- &mut self.element_mut().tag
- }
- /// Get a reference to the namespace the element is in
- pub fn namespace(&self) -> Option<&str> {
- self.element().namespace.as_deref()
- }
- /// Get a mutable reference to the namespace the element is in
- pub fn namespace_mut(&mut self) -> &mut Option<String> {
- self.dirty_nodes
- .mark_dirty(self.id, NodeMaskBuilder::new().with_namespace().build());
- &mut self.element_mut().namespace
- }
- /// Get a reference to all of the attributes currently set on the element
- pub fn attributes(&self) -> &FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue<V>> {
- &self.element().attributes
- }
- /// Set an attribute in the element
- pub fn set_attribute(
- &mut self,
- name: impl Into<OwnedAttributeDiscription>,
- value: impl Into<OwnedAttributeValue<V>>,
- ) -> Option<OwnedAttributeValue<V>> {
- let name = name.into();
- let value = value.into();
- self.dirty_nodes.mark_dirty(
- self.id,
- NodeMaskBuilder::new()
- .with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
- .build(),
- );
- self.element_mut().attributes.insert(name, value)
- }
- /// Remove an attribute from the element
- pub fn remove_attribute(
- &mut self,
- name: &OwnedAttributeDiscription,
- ) -> Option<OwnedAttributeValue<V>> {
- self.dirty_nodes.mark_dirty(
- self.id,
- NodeMaskBuilder::new()
- .with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
- .build(),
- );
- self.element_mut().attributes.remove(name)
- }
- /// Get an attribute of the element
- pub fn get_attribute_mut(
- &mut self,
- name: &OwnedAttributeDiscription,
- ) -> Option<&mut OwnedAttributeValue<V>> {
- self.dirty_nodes.mark_dirty(
- self.id,
- NodeMaskBuilder::new()
- .with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
- .build(),
- );
- self.element_mut().attributes.get_mut(name)
- }
- /// Get the set of all events the element is listening to
- pub fn listeners(&self) -> &FxHashSet<String> {
- &self.element().listeners
- }
- }
- // Create a workload from all of the passes. This orders the passes so that each pass will only run at most once.
- fn construct_workload<V: FromAnyValue + Send + Sync>(
- passes: &mut [TypeErasedState<V>],
- ) -> Workload {
- let mut workload = Workload::new("Main Workload");
- // Assign a unique index to keep track of each pass
- let mut unresloved_workloads = passes
- .iter_mut()
- .enumerate()
- .map(|(i, pass)| {
- let workload = Some(pass.create_workload());
- (i, pass, workload)
- })
- .collect::<Vec<_>>();
- // set all the labels
- for (id, _, workload) in &mut unresloved_workloads {
- *workload = Some(workload.take().unwrap().tag(id.to_string()));
- }
- // mark any dependancies
- for i in 0..unresloved_workloads.len() {
- let (_, pass, _) = &unresloved_workloads[i];
- let all_dependancies: Vec<_> = pass.combined_dependancy_type_ids().collect();
- for ty_id in all_dependancies {
- let &(dependancy_id, _, _) = unresloved_workloads
- .iter()
- .find(|(_, pass, _)| pass.this_type_id == ty_id)
- .unwrap();
- let (_, _, workload) = &mut unresloved_workloads[i];
- *workload = workload
- .take()
- .map(|workload| workload.after_all(dependancy_id.to_string()));
- }
- }
- // Add all of the passes
- for (_, _, mut workload_system) in unresloved_workloads {
- workload = workload.with_system(workload_system.take().unwrap());
- }
- workload
- }
|