123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- use anymap::AnyMap;
- use fxhash::{FxHashMap, FxHashSet};
- use std::{
- any::TypeId,
- collections::VecDeque,
- ops::{Index, IndexMut},
- };
- use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
- use crate::state::{union_ordered_iter, AttributeMask, NodeMask, State};
- /// 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 implement [PushedDownState] and or [BubbledUpState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes.
- #[derive(Debug)]
- pub struct RealDom<S: State> {
- root: usize,
- nodes: Vec<Option<Node<S>>>,
- nodes_listening: FxHashMap<&'static str, FxHashSet<usize>>,
- node_stack: smallvec::SmallVec<[usize; 10]>,
- }
- impl<S: State> Default for RealDom<S> {
- fn default() -> Self {
- Self::new()
- }
- }
- impl<S: State> RealDom<S> {
- pub fn new() -> RealDom<S> {
- RealDom {
- root: 0,
- nodes: {
- let v = vec![Some(Node::new(
- 0,
- NodeType::Element {
- tag: "Root".to_string(),
- namespace: Some("Root"),
- children: Vec::new(),
- },
- ))];
- v
- },
- nodes_listening: FxHashMap::default(),
- node_stack: smallvec::SmallVec::new(),
- }
- }
- /// Updates the dom, up and down state and return a set of nodes that were updated pass this to update_state.
- pub fn apply_mutations(&mut self, mutations_vec: Vec<Mutations>) -> Vec<(usize, NodeMask)> {
- let mut nodes_updated = Vec::new();
- for mutations in mutations_vec {
- for e in mutations.edits {
- use dioxus_core::DomEdit::*;
- match e {
- PushRoot { root } => self.node_stack.push(root as usize),
- AppendChildren { many } => {
- let target = if self.node_stack.len() > many as usize {
- *self
- .node_stack
- .get(self.node_stack.len() - (many as usize + 1))
- .unwrap()
- } else {
- 0
- };
- let drained: Vec<_> = self
- .node_stack
- .drain(self.node_stack.len() - many as usize..)
- .collect();
- for ns in drained {
- self.link_child(ns, target).unwrap();
- nodes_updated.push((ns, NodeMask::ALL));
- }
- }
- ReplaceWith { root, m } => {
- let root = self.remove(root as usize).unwrap();
- let target = root.parent.unwrap().0;
- let drained: Vec<_> = self.node_stack.drain(0..m as usize).collect();
- for ns in drained {
- nodes_updated.push((ns, NodeMask::ALL));
- self.link_child(ns, target).unwrap();
- }
- }
- InsertAfter { root, n } => {
- let target = self[root as usize].parent.unwrap().0;
- let drained: Vec<_> = self.node_stack.drain(0..n as usize).collect();
- for ns in drained {
- nodes_updated.push((ns, NodeMask::ALL));
- self.link_child(ns, target).unwrap();
- }
- }
- InsertBefore { root, n } => {
- let target = self[root as usize].parent.unwrap().0;
- let drained: Vec<_> = self.node_stack.drain(0..n as usize).collect();
- for ns in drained {
- nodes_updated.push((ns, NodeMask::ALL));
- self.link_child(ns, target).unwrap();
- }
- }
- Remove { root } => {
- if let Some(parent) = self[root as usize].parent {
- nodes_updated.push((parent.0, NodeMask::NONE));
- }
- self.remove(root as usize).unwrap();
- }
- CreateTextNode { root, text } => {
- let n = Node::new(
- root,
- NodeType::Text {
- text: text.to_string(),
- },
- );
- self.insert(n);
- self.node_stack.push(root as usize)
- }
- CreateElement { root, tag } => {
- let n = Node::new(
- root,
- NodeType::Element {
- tag: tag.to_string(),
- namespace: None,
- children: Vec::new(),
- },
- );
- self.insert(n);
- self.node_stack.push(root as usize)
- }
- CreateElementNs { root, tag, ns } => {
- let n = Node::new(
- root,
- NodeType::Element {
- tag: tag.to_string(),
- namespace: Some(ns),
- children: Vec::new(),
- },
- );
- self.insert(n);
- self.node_stack.push(root as usize)
- }
- CreatePlaceholder { root } => {
- let n = Node::new(root, NodeType::Placeholder);
- self.insert(n);
- self.node_stack.push(root as usize)
- }
- NewEventListener {
- event_name,
- scope: _,
- root,
- } => {
- if let Some(v) = self.nodes_listening.get_mut(event_name) {
- v.insert(root as usize);
- } else {
- let mut hs = FxHashSet::default();
- hs.insert(root as usize);
- self.nodes_listening.insert(event_name, hs);
- }
- }
- RemoveEventListener { root, event } => {
- let v = self.nodes_listening.get_mut(event).unwrap();
- v.remove(&(root as usize));
- }
- SetText {
- root,
- text: new_text,
- } => {
- let target = &mut self[root as usize];
- nodes_updated.push((
- root as usize,
- NodeMask::new(AttributeMask::NONE, false, false, true),
- ));
- match &mut target.node_type {
- NodeType::Text { text } => {
- *text = new_text.to_string();
- }
- _ => unreachable!(),
- }
- }
- SetAttribute { root, field, .. } => {
- nodes_updated.push((
- root as usize,
- NodeMask::new(AttributeMask::single(field), false, false, false),
- ));
- }
- RemoveAttribute {
- root, name: field, ..
- } => {
- nodes_updated.push((
- root as usize,
- NodeMask::new(AttributeMask::single(field), false, false, false),
- ));
- }
- PopRoot {} => {
- self.node_stack.pop();
- }
- }
- }
- }
- nodes_updated
- }
- /// Seperated from apply_mutations because Mutations require a mutable reference to the VirtualDom.
- pub fn update_state(
- &mut self,
- vdom: &VirtualDom,
- nodes_updated: Vec<(usize, NodeMask)>,
- ctx: AnyMap,
- ) -> Option<FxHashSet<usize>> {
- #[derive(PartialEq, Clone, Debug)]
- enum StatesToCheck {
- All,
- Some(Vec<TypeId>),
- }
- impl StatesToCheck {
- fn union(&self, other: &Self) -> Self {
- match (self, other) {
- (Self::Some(s), Self::Some(o)) => Self::Some(union_ordered_iter(
- s.iter().copied(),
- o.iter().copied(),
- s.len() + o.len(),
- )),
- _ => Self::All,
- }
- }
- }
- #[derive(Debug, Clone)]
- struct NodeRef {
- id: usize,
- height: u16,
- node_mask: NodeMask,
- to_check: StatesToCheck,
- }
- impl NodeRef {
- fn union_with(&mut self, other: &Self) {
- self.node_mask = self.node_mask.union(&other.node_mask);
- self.to_check = self.to_check.union(&other.to_check);
- }
- }
- impl Eq for NodeRef {}
- impl PartialEq for NodeRef {
- fn eq(&self, other: &Self) -> bool {
- self.id == other.id && self.height == other.height
- }
- }
- impl Ord for NodeRef {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- self.partial_cmp(other).unwrap()
- }
- }
- impl PartialOrd for NodeRef {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- // Sort nodes first by height, then if the height is the same id.
- // The order of the id does not matter it just helps with binary search later
- Some(self.height.cmp(&other.height).then(self.id.cmp(&other.id)))
- }
- }
- let mut to_rerender = FxHashSet::default();
- to_rerender.extend(nodes_updated.iter().map(|(id, _)| id));
- let mut nodes_updated: Vec<_> = nodes_updated
- .into_iter()
- .map(|(id, mask)| NodeRef {
- id,
- height: self[id].height,
- node_mask: mask,
- to_check: StatesToCheck::All,
- })
- .collect();
- nodes_updated.sort();
- // Combine mutations that affect the same node.
- let mut last_node: Option<NodeRef> = None;
- let mut new_nodes_updated = VecDeque::new();
- for current in nodes_updated.into_iter() {
- if let Some(node) = &mut last_node {
- if *node == current {
- node.union_with(¤t);
- } else {
- new_nodes_updated.push_back(last_node.replace(current).unwrap());
- }
- } else {
- last_node = Some(current);
- }
- }
- if let Some(node) = last_node {
- new_nodes_updated.push_back(node);
- }
- let nodes_updated = new_nodes_updated;
- // update the state that only depends on nodes. The order does not matter.
- for node_ref in &nodes_updated {
- let mut changed = false;
- let node = &mut self[node_ref.id];
- let ids = match &node_ref.to_check {
- StatesToCheck::All => node.state.node_dep_types(&node_ref.node_mask),
- StatesToCheck::Some(_) => unreachable!(),
- };
- for ty in ids {
- let node = &mut self[node_ref.id];
- let vnode = node.element(vdom);
- changed |= node.state.update_node_dep_state(ty, vnode, vdom, &ctx);
- }
- if changed {
- to_rerender.insert(node_ref.id);
- }
- }
- // bubble up state. To avoid calling reduce more times than nessisary start from the bottom and go up.
- let mut to_bubble = nodes_updated.clone();
- while let Some(node_ref) = to_bubble.pop_back() {
- let NodeRef {
- id,
- height,
- node_mask,
- to_check,
- } = node_ref;
- let (node, children) = self.get_node_children_mut(id).unwrap();
- let children_state: Vec<_> = children.iter().map(|c| &c.state).collect();
- let ids = match to_check {
- StatesToCheck::All => node.state.child_dep_types(&node_mask),
- StatesToCheck::Some(ids) => ids,
- };
- let mut changed = Vec::new();
- for ty in ids {
- let vnode = node.element(vdom);
- if node
- .state
- .update_child_dep_state(ty, vnode, vdom, &children_state, &ctx)
- {
- changed.push(ty);
- }
- }
- if let Some(parent_id) = node.parent {
- if !changed.is_empty() {
- to_rerender.insert(id);
- let i = to_bubble.partition_point(
- |NodeRef {
- id: other_id,
- height: h,
- ..
- }| {
- *h < height - 1 || (*h == height - 1 && *other_id < parent_id.0)
- },
- );
- // make sure the parent is not already queued
- if i < to_bubble.len() && to_bubble[i].id == parent_id.0 {
- to_bubble[i].to_check =
- to_bubble[i].to_check.union(&StatesToCheck::Some(changed));
- } else {
- to_bubble.insert(
- i,
- NodeRef {
- id: parent_id.0,
- height: height - 1,
- node_mask: NodeMask::NONE,
- to_check: StatesToCheck::Some(changed),
- },
- );
- }
- }
- }
- }
- // push down state. To avoid calling reduce more times than nessisary start from the top and go down.
- let mut to_push = nodes_updated.clone();
- while let Some(node_ref) = to_push.pop_front() {
- let NodeRef {
- id,
- height,
- node_mask,
- to_check,
- } = node_ref;
- let node = &self[id];
- let ids = match to_check {
- StatesToCheck::All => node.state.parent_dep_types(&node_mask),
- StatesToCheck::Some(ids) => ids,
- };
- let mut changed = Vec::new();
- let (node, parent) = self.get_node_parent_mut(id).unwrap();
- for ty in ids {
- let vnode = node.element(vdom);
- let parent = parent.as_deref();
- let state = &mut node.state;
- if state.update_parent_dep_state(ty, vnode, vdom, parent.map(|n| &n.state), &ctx) {
- changed.push(ty);
- }
- }
- to_rerender.insert(id);
- if !changed.is_empty() {
- let node = &self[id];
- if let NodeType::Element { children, .. } = &node.node_type {
- for c in children {
- let i = to_push.partition_point(
- |NodeRef {
- id: other_id,
- height: h,
- ..
- }| {
- *h < height + 1 || (*h == height + 1 && *other_id < c.0)
- },
- );
- if i < to_push.len() && to_push[i].id == c.0 {
- to_push[i].to_check = to_push[i]
- .to_check
- .union(&StatesToCheck::Some(changed.clone()));
- } else {
- to_push.insert(
- i,
- NodeRef {
- id: c.0,
- height: height + 1,
- node_mask: NodeMask::NONE,
- to_check: StatesToCheck::Some(changed.clone()),
- },
- );
- }
- }
- }
- }
- }
- Some(to_rerender)
- }
- fn link_child(&mut self, child_id: usize, parent_id: usize) -> Option<()> {
- debug_assert_ne!(child_id, parent_id);
- let parent = &mut self[parent_id];
- parent.add_child(ElementId(child_id));
- let parent_height = parent.height + 1;
- self[child_id].set_parent(ElementId(parent_id));
- self.increase_height(child_id, parent_height);
- Some(())
- }
- fn increase_height(&mut self, id: usize, amount: u16) {
- let n = &mut self[id];
- n.height += amount;
- if let NodeType::Element { children, .. } = &n.node_type {
- for c in children.clone() {
- self.increase_height(c.0, amount);
- }
- }
- }
- // remove a node and it's children from the dom.
- fn remove(&mut self, id: usize) -> Option<Node<S>> {
- // We do not need to remove the node from the parent's children list for children.
- fn inner<S: State>(dom: &mut RealDom<S>, id: usize) -> Option<Node<S>> {
- let mut node = dom.nodes[id as usize].take()?;
- if let NodeType::Element { children, .. } = &mut node.node_type {
- for c in children {
- inner(dom, c.0)?;
- }
- }
- Some(node)
- }
- let mut node = self.nodes[id as usize].take()?;
- if let Some(parent) = node.parent {
- let parent = &mut self[parent];
- parent.remove_child(ElementId(id));
- }
- if let NodeType::Element { children, .. } = &mut node.node_type {
- for c in children {
- inner(self, c.0)?;
- }
- }
- Some(node)
- }
- fn insert(&mut self, node: Node<S>) {
- let current_len = self.nodes.len();
- let id = node.id.0;
- if current_len - 1 < node.id.0 {
- // self.nodes.reserve(1 + id - current_len);
- self.nodes.extend((0..1 + id - current_len).map(|_| None));
- }
- self.nodes[id] = Some(node);
- }
- pub fn get(&self, id: usize) -> Option<&Node<S>> {
- self.nodes.get(id)?.as_ref()
- }
- pub fn get_mut(&mut self, id: usize) -> Option<&mut Node<S>> {
- self.nodes.get_mut(id)?.as_mut()
- }
- // this is safe because no node will have itself as a child
- pub fn get_node_children_mut<'a>(
- &'a mut self,
- id: usize,
- ) -> Option<(&'a mut Node<S>, Vec<&'a mut Node<S>>)> {
- let ptr = self.nodes.as_mut_ptr();
- unsafe {
- if id >= self.nodes.len() {
- None
- } else {
- let node = &mut *ptr.add(id);
- if let Some(node) = node.as_mut() {
- let children = match &node.node_type {
- NodeType::Element { children, .. } => children
- .iter()
- .map(|id| (&mut *ptr.add(id.0)).as_mut().unwrap())
- .collect(),
- _ => Vec::new(),
- };
- return Some((node, children));
- } else {
- None
- }
- }
- }
- }
- // this is safe because no node will have itself as a parent
- pub fn get_node_parent_mut<'a>(
- &'a mut self,
- id: usize,
- ) -> Option<(&'a mut Node<S>, Option<&'a mut Node<S>>)> {
- let ptr = self.nodes.as_mut_ptr();
- unsafe {
- let node = &mut *ptr.add(id);
- if id >= self.nodes.len() {
- None
- } else {
- if let Some(node) = node.as_mut() {
- let parent = node
- .parent
- .map(|id| (&mut *ptr.add(id.0)).as_mut().unwrap());
- return Some((node, parent));
- } else {
- None
- }
- }
- }
- }
- pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&Node<S>> {
- if let Some(nodes) = self.nodes_listening.get(event) {
- let mut listening: Vec<_> = nodes.iter().map(|id| &self[*id]).collect();
- listening.sort_by(|n1, n2| (n1.height).cmp(&n2.height).reverse());
- listening
- } else {
- Vec::new()
- }
- }
- /// Check if the dom contains a node and its children.
- pub fn contains_node(&self, node: &VNode) -> bool {
- match node {
- VNode::Component(_) => {
- todo!()
- }
- VNode::Element(e) => {
- if let Some(id) = e.id.get() {
- let dom_node = &self[id];
- match &dom_node.node_type {
- NodeType::Element {
- tag,
- namespace,
- children,
- } => {
- tag == e.tag
- && namespace == &e.namespace
- && children.iter().copied().collect::<FxHashSet<_>>()
- == e.children
- .iter()
- .map(|c| c.mounted_id())
- .collect::<FxHashSet<_>>()
- && e.children.iter().all(|c| {
- self.contains_node(c)
- && self[c.mounted_id()].parent == e.id.get()
- })
- }
- _ => false,
- }
- } else {
- true
- }
- }
- VNode::Fragment(f) => f.children.iter().all(|c| self.contains_node(c)),
- VNode::Placeholder(_) => true,
- VNode::Text(t) => {
- if let Some(id) = t.id.get() {
- let dom_node = &self[id];
- match &dom_node.node_type {
- NodeType::Text { text } => t.text == text,
- _ => false,
- }
- } else {
- true
- }
- }
- }
- }
- /// Return the number of nodes in the dom.
- pub fn size(&self) -> usize {
- // The dom has a root node, ignore it.
- self.nodes.iter().filter(|n| n.is_some()).count() - 1
- }
- /// Returns the id of the root node.
- pub fn root_id(&self) -> usize {
- self.root
- }
- /// Call a function for each node in the dom, depth first.
- pub fn traverse_depth_first(&self, mut f: impl FnMut(&Node<S>)) {
- fn inner<S: State>(dom: &RealDom<S>, id: ElementId, f: &mut impl FnMut(&Node<S>)) {
- let node = &dom[id];
- f(node);
- if let NodeType::Element { children, .. } = &node.node_type {
- for c in children {
- inner(dom, *c, f);
- }
- }
- }
- if let NodeType::Element { children, .. } = &self[self.root].node_type {
- for c in children {
- inner(self, *c, &mut f);
- }
- }
- }
- /// Call a function for each node in the dom, depth first.
- pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut Node<S>)) {
- fn inner<S: State>(dom: &mut RealDom<S>, id: ElementId, f: &mut impl FnMut(&mut Node<S>)) {
- let node = &mut dom[id];
- f(node);
- if let NodeType::Element { children, .. } = &mut node.node_type {
- for c in children.clone() {
- inner(dom, c, f);
- }
- }
- }
- let root = self.root;
- if let NodeType::Element { children, .. } = &mut self[root].node_type {
- for c in children.clone() {
- inner(self, c, &mut f);
- }
- }
- }
- }
- impl<S: State> Index<usize> for RealDom<S> {
- type Output = Node<S>;
- fn index(&self, idx: usize) -> &Self::Output {
- self.get(idx).expect("Node does not exist")
- }
- }
- impl<S: State> Index<ElementId> for RealDom<S> {
- type Output = Node<S>;
- fn index(&self, idx: ElementId) -> &Self::Output {
- &self[idx.0]
- }
- }
- impl<S: State> IndexMut<usize> for RealDom<S> {
- fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
- self.get_mut(idx).expect("Node does not exist")
- }
- }
- impl<S: State> IndexMut<ElementId> for RealDom<S> {
- fn index_mut(&mut self, idx: ElementId) -> &mut Self::Output {
- &mut self[idx.0]
- }
- }
- /// The node is stored client side and stores only basic data about the node. For more complete information about the node see [`domNode::element`].
- #[derive(Debug, Clone)]
- pub struct Node<S: State> {
- /// The id of the node this node was created from.
- pub id: ElementId,
- /// The parent id of the node.
- pub parent: Option<ElementId>,
- /// State of the node.
- pub state: S,
- /// Additional inforation specific to the node type
- pub node_type: NodeType,
- /// The number of parents before the root node. The root node has height 1.
- pub height: u16,
- }
- #[derive(Debug, Clone)]
- pub enum NodeType {
- Text {
- text: String,
- },
- Element {
- tag: String,
- namespace: Option<&'static str>,
- children: Vec<ElementId>,
- },
- Placeholder,
- }
- impl<S: State> Node<S> {
- fn new(id: u64, node_type: NodeType) -> Self {
- Node {
- id: ElementId(id as usize),
- parent: None,
- node_type,
- state: S::default(),
- height: 0,
- }
- }
- /// Returns a reference to the element that this node refrences.
- pub fn element<'b>(&self, vdom: &'b VirtualDom) -> &'b VNode<'b> {
- vdom.get_element(self.id).unwrap()
- }
- fn add_child(&mut self, child: ElementId) {
- if let NodeType::Element { children, .. } = &mut self.node_type {
- children.push(child);
- }
- }
- fn remove_child(&mut self, child: ElementId) {
- if let NodeType::Element { children, .. } = &mut self.node_type {
- children.retain(|c| c != &child);
- }
- }
- fn set_parent(&mut self, parent: ElementId) {
- self.parent = Some(parent);
- }
- }
|