patch.rs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. use fxhash::FxHashMap;
  2. use crate::innerlude::{VNode, VText};
  3. /// A Patch encodes an operation that modifies a real DOM element.
  4. ///
  5. /// To update the real DOM that a user sees you'll want to first diff your
  6. /// old virtual dom and new virtual dom.
  7. ///
  8. /// This diff operation will generate `Vec<Patch>` with zero or more patches that, when
  9. /// applied to your real DOM, will make your real DOM look like your new virtual dom.
  10. ///
  11. /// Each Patch has a u32 node index that helps us identify the real DOM node that it applies to.
  12. ///
  13. /// Our old virtual dom's nodes are indexed depth first, as shown in this illustration
  14. /// (0 being the root node, 1 being it's first child, 2 being it's first child's first child).
  15. ///
  16. /// ```text
  17. /// .─.
  18. /// ( 0 )
  19. /// `┬'
  20. /// ┌────┴──────┐
  21. /// │ │
  22. /// ▼ ▼
  23. /// .─. .─.
  24. /// ( 1 ) ( 4 )
  25. /// `┬' `─'
  26. /// ┌────┴───┐ ├─────┬─────┐
  27. /// │ │ │ │ │
  28. /// ▼ ▼ ▼ ▼ ▼
  29. /// .─. .─. .─. .─. .─.
  30. /// ( 2 ) ( 3 ) ( 5 ) ( 6 ) ( 7 )
  31. /// `─' `─' `─' `─' `─'
  32. /// ```
  33. ///
  34. /// The patching process is tested in a real browser in crates/virtual-dom-rs/tests/diff_patch.rs
  35. // #[derive(serde::Serialize, serde::Deserialize)]
  36. pub enum Patch<'a> {
  37. /// Append a vector of child nodes to a parent node id.
  38. AppendChildren(NodeIdx, Vec<&'a VNode<'a>>),
  39. /// For a `node_i32`, remove all children besides the first `len`
  40. TruncateChildren(NodeIdx, usize),
  41. /// Replace a node with another node. This typically happens when a node's tag changes.
  42. /// ex: <div> becomes <span>
  43. Replace(NodeIdx, &'a VNode<'a>),
  44. /// Add attributes that the new node has that the old node does not
  45. AddAttributes(NodeIdx, FxHashMap<&'a str, &'a str>),
  46. /// Remove attributes that the old node had that the new node doesn't
  47. RemoveAttributes(NodeIdx, Vec<&'a str>),
  48. /// Change the text of a Text node.
  49. ChangeText(NodeIdx, &'a VText<'a>),
  50. }
  51. type NodeIdx = usize;
  52. impl<'a> Patch<'a> {
  53. /// Every Patch is meant to be applied to a specific node within the DOM. Get the
  54. /// index of the DOM node that this patch should apply to. DOM nodes are indexed
  55. /// depth first with the root node in the tree having index 0.
  56. pub fn node_idx(&self) -> usize {
  57. match self {
  58. Patch::AppendChildren(node_idx, _) => *node_idx,
  59. Patch::TruncateChildren(node_idx, _) => *node_idx,
  60. Patch::Replace(node_idx, _) => *node_idx,
  61. Patch::AddAttributes(node_idx, _) => *node_idx,
  62. Patch::RemoveAttributes(node_idx, _) => *node_idx,
  63. Patch::ChangeText(node_idx, _) => *node_idx,
  64. }
  65. }
  66. }
  67. pub struct PatchList<'a> {
  68. patches: Vec<Patch<'a>>,
  69. }