123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- use crate::{arena::ElementId, AttributeValue, Template};
- /// Something that can handle the mutations that are generated by the diffing process and apply them to the Real DOM
- ///
- /// This object provides a bunch of important information for a renderer to use patch the Real Dom with the state of the
- /// VirtualDom. This includes the scopes that were modified, the templates that were discovered, and a list of changes
- /// in the form of a [`Mutation`].
- ///
- /// These changes are specific to one subtree, so to patch multiple subtrees, you'd need to handle each set separately.
- ///
- /// Templates, however, apply to all subtrees, not just target subtree.
- ///
- /// Mutations are the only link between the RealDOM and the VirtualDOM.
- pub trait WriteMutations {
- /// Add these m children to the target element
- ///
- /// Id: The ID of the element being mounted to
- /// M: The number of nodes on the stack to append to the target element
- fn append_children(&mut self, id: ElementId, m: usize);
- /// Assign the element at the given path the target ElementId.
- ///
- /// The path is in the form of a list of indices based on children. Templates cannot have more than 255 children per
- /// element, hence the use of a single byte.
- ///
- /// Path: The path of the child of the topmost node on the stack. A path of `[]` represents the topmost node. A path of `[0]` represents the first child. `[0,1,2]` represents 1st child's 2nd child's 3rd child.
- /// Id: The ID we're assigning to this element/placeholder. This will be used later to modify the element or replace it with another element.
- fn assign_node_id(&mut self, path: &'static [u8], id: ElementId);
- /// Create a placeholder in the DOM that we will use later.
- ///
- /// Dioxus currently requires the use of placeholders to maintain a re-entrance point for things like list diffing
- ///
- /// Id: The ID we're assigning to this element/placeholder. This will be used later to modify the element or replace it with another element.
- fn create_placeholder(&mut self, id: ElementId);
- /// Create a node specifically for text with the given value
- ///
- /// Value: The text content of this text node
- /// Id: The ID we're assigning to this specific text nodes. This will be used later to modify the element or replace it with another element.
- fn create_text_node(&mut self, value: &str, id: ElementId);
- /// Load and clone an existing node from a template saved under that specific name
- ///
- /// Dioxus guarantees that the renderer will have already been provided the template.
- /// When the template is picked up in the template list, it should be saved under its "name" - here, the name
- ///
- /// Name: The unique "name" of the template based on the template location. When paired with `rsx!`, this is autogenerated
- /// Index: The index root we loading from the template. The template is stored as a list of nodes. This index represents the position of that root
- /// Id: The ID we're assigning to this element being loaded from the template (This will be used later to move the element around in lists)
- fn load_template(&mut self, template: Template, index: usize, id: ElementId);
- /// Replace the target element (given by its ID) with the topmost m nodes on the stack
- ///
- /// id: The ID of the node we're going to replace with new nodes
- /// m: The number of nodes on the stack to replace the target element with
- fn replace_node_with(&mut self, id: ElementId, m: usize);
- /// Replace an existing element in the template at the given path with the m nodes on the stack
- ///
- /// Path: The path of the child of the topmost node on the stack. A path of `[]` represents the topmost node. A path of `[0]` represents the first child. `[0,1,2]` represents 1st child's 2nd child's 3rd child.
- /// M: The number of nodes on the stack to replace the target element with
- fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize);
- /// Insert a number of nodes after a given node.
- ///
- /// Id: The ID of the node to insert after.
- /// M: The number of nodes on the stack to insert after the target node.
- fn insert_nodes_after(&mut self, id: ElementId, m: usize);
- /// Insert a number of nodes before a given node.
- ///
- /// Id: The ID of the node to insert before.
- /// M: The number of nodes on the stack to insert before the target node.
- fn insert_nodes_before(&mut self, id: ElementId, m: usize);
- /// Set the value of a node's attribute.
- ///
- /// Name: The name of the attribute to set.
- /// NS: The (optional) namespace of the attribute. For instance, "style" is in the "style" namespace.
- /// Value: The value of the attribute.
- /// Id: The ID of the node to set the attribute of.
- fn set_attribute(
- &mut self,
- name: &'static str,
- ns: Option<&'static str>,
- value: &AttributeValue,
- id: ElementId,
- );
- /// Set the text content of a node.
- ///
- /// Value: The textcontent of the node
- /// Id: The ID of the node to set the textcontent of.
- fn set_node_text(&mut self, value: &str, id: ElementId);
- /// Create a new Event Listener.
- ///
- /// Name: The name of the event to listen for.
- /// Id: The ID of the node to attach the listener to.
- fn create_event_listener(&mut self, name: &'static str, id: ElementId);
- /// Remove an existing Event Listener.
- ///
- /// Name: The name of the event to remove.
- /// Id: The ID of the node to remove.
- fn remove_event_listener(&mut self, name: &'static str, id: ElementId);
- /// Remove a particular node from the DOM
- ///
- /// Id: The ID of the node to remove.
- fn remove_node(&mut self, id: ElementId);
- /// Push the given root node onto our stack.
- ///
- /// Id: The ID of the root node to push.
- fn push_root(&mut self, id: ElementId);
- }
- /// A `Mutation` represents a single instruction for the renderer to use to modify the UI tree to match the state
- /// of the Dioxus VirtualDom.
- ///
- /// These edits can be serialized and sent over the network or through any interface
- #[derive(Debug, PartialEq)]
- pub enum Mutation {
- /// Add these m children to the target element
- AppendChildren {
- /// The ID of the element being mounted to
- id: ElementId,
- /// The number of nodes on the stack to append to the target element
- m: usize,
- },
- /// Assign the element at the given path the target ElementId.
- ///
- /// The path is in the form of a list of indices based on children. Templates cannot have more than 255 children per
- /// element, hence the use of a single byte.
- AssignId {
- /// The path of the child of the topmost node on the stack
- ///
- /// A path of `[]` represents the topmost node. A path of `[0]` represents the first child.
- /// `[0,1,2]` represents 1st child's 2nd child's 3rd child.
- path: &'static [u8],
- /// The ID we're assigning to this element/placeholder.
- ///
- /// This will be used later to modify the element or replace it with another element.
- id: ElementId,
- },
- /// Create a placeholder in the DOM that we will use later.
- ///
- /// Dioxus currently requires the use of placeholders to maintain a re-entrance point for things like list diffing
- CreatePlaceholder {
- /// The ID we're assigning to this element/placeholder.
- ///
- /// This will be used later to modify the element or replace it with another element.
- id: ElementId,
- },
- /// Create a node specifically for text with the given value
- CreateTextNode {
- /// The text content of this text node
- value: String,
- /// The ID we're assigning to this specific text nodes
- ///
- /// This will be used later to modify the element or replace it with another element.
- id: ElementId,
- },
- /// Load and clone an existing node from a template with a given ID
- ///
- /// Dioxus guarantees that the renderer will have already been provided the template.
- /// When the template is picked up in the template list, it should be saved under its "name" - here, the name
- LoadTemplate {
- /// Which root are we loading from the template?
- ///
- /// The template is stored as a list of nodes. This index represents the position of that root
- index: usize,
- /// The ID we're assigning to this element being loaded from the template
- ///
- /// This will be used later to move the element around in lists
- id: ElementId,
- },
- /// Replace the target element (given by its ID) with the topmost m nodes on the stack
- ReplaceWith {
- /// The ID of the node we're going to replace with
- id: ElementId,
- /// The number of nodes on the stack to replace the target element with
- m: usize,
- },
- /// Replace an existing element in the template at the given path with the m nodes on the stack
- ReplacePlaceholder {
- /// The path of the child of the topmost node on the stack
- ///
- /// A path of `[]` represents the topmost node. A path of `[0]` represents the first child.
- /// `[0,1,2]` represents 1st child's 2nd child's 3rd child.
- path: &'static [u8],
- /// The number of nodes on the stack to replace the target element with
- m: usize,
- },
- /// Insert a number of nodes after a given node.
- InsertAfter {
- /// The ID of the node to insert after.
- id: ElementId,
- /// The number of nodes on the stack to insert after the target node.
- m: usize,
- },
- /// Insert a number of nodes before a given node.
- InsertBefore {
- /// The ID of the node to insert before.
- id: ElementId,
- /// The number of nodes on the stack to insert before the target node.
- m: usize,
- },
- /// Set the value of a node's attribute.
- SetAttribute {
- /// The name of the attribute to set.
- name: &'static str,
- /// The (optional) namespace of the attribute.
- /// For instance, "style" is in the "style" namespace.
- ns: Option<&'static str>,
- /// The value of the attribute.
- value: AttributeValue,
- /// The ID of the node to set the attribute of.
- id: ElementId,
- },
- /// Set the textcontent of a node.
- SetText {
- /// The textcontent of the node
- value: String,
- /// The ID of the node to set the textcontent of.
- id: ElementId,
- },
- /// Create a new Event Listener.
- NewEventListener {
- /// The name of the event to listen for.
- name: String,
- /// The ID of the node to attach the listener to.
- id: ElementId,
- },
- /// Remove an existing Event Listener.
- RemoveEventListener {
- /// The name of the event to remove.
- name: String,
- /// The ID of the node to remove.
- id: ElementId,
- },
- /// Remove a particular node from the DOM
- Remove {
- /// The ID of the node to remove.
- id: ElementId,
- },
- /// Push the given root node onto our stack.
- PushRoot {
- /// The ID of the root node to push.
- id: ElementId,
- },
- }
- /// A static list of mutations that can be applied to the DOM. Note: this list does not contain any `Any` attribute values
- #[derive(Debug, PartialEq, Default)]
- pub struct Mutations {
- /// Any mutations required to patch the renderer to match the layout of the VirtualDom
- pub edits: Vec<Mutation>,
- }
- impl WriteMutations for Mutations {
- fn append_children(&mut self, id: ElementId, m: usize) {
- self.edits.push(Mutation::AppendChildren { id, m })
- }
- fn assign_node_id(&mut self, path: &'static [u8], id: ElementId) {
- self.edits.push(Mutation::AssignId { path, id })
- }
- fn create_placeholder(&mut self, id: ElementId) {
- self.edits.push(Mutation::CreatePlaceholder { id })
- }
- fn create_text_node(&mut self, value: &str, id: ElementId) {
- self.edits.push(Mutation::CreateTextNode {
- value: value.into(),
- id,
- })
- }
- fn load_template(&mut self, _template: Template, index: usize, id: ElementId) {
- self.edits.push(Mutation::LoadTemplate { index, id })
- }
- fn replace_node_with(&mut self, id: ElementId, m: usize) {
- self.edits.push(Mutation::ReplaceWith { id, m })
- }
- fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize) {
- self.edits.push(Mutation::ReplacePlaceholder { path, m })
- }
- fn insert_nodes_after(&mut self, id: ElementId, m: usize) {
- self.edits.push(Mutation::InsertAfter { id, m })
- }
- fn insert_nodes_before(&mut self, id: ElementId, m: usize) {
- self.edits.push(Mutation::InsertBefore { id, m })
- }
- fn set_attribute(
- &mut self,
- name: &'static str,
- ns: Option<&'static str>,
- value: &AttributeValue,
- id: ElementId,
- ) {
- self.edits.push(Mutation::SetAttribute {
- name,
- ns,
- value: match value {
- AttributeValue::Text(s) => AttributeValue::Text(s.clone()),
- AttributeValue::Bool(b) => AttributeValue::Bool(*b),
- AttributeValue::Float(n) => AttributeValue::Float(*n),
- AttributeValue::Int(n) => AttributeValue::Int(*n),
- AttributeValue::None => AttributeValue::None,
- _ => panic!("Cannot serialize attribute value"),
- },
- id,
- })
- }
- fn set_node_text(&mut self, value: &str, id: ElementId) {
- self.edits.push(Mutation::SetText {
- value: value.into(),
- id,
- })
- }
- fn create_event_listener(&mut self, name: &'static str, id: ElementId) {
- self.edits.push(Mutation::NewEventListener {
- name: name.into(),
- id,
- })
- }
- fn remove_event_listener(&mut self, name: &'static str, id: ElementId) {
- self.edits.push(Mutation::RemoveEventListener {
- name: name.into(),
- id,
- })
- }
- fn remove_node(&mut self, id: ElementId) {
- self.edits.push(Mutation::Remove { id })
- }
- fn push_root(&mut self, id: ElementId) {
- self.edits.push(Mutation::PushRoot { id })
- }
- }
- /// A struct that ignores all mutations
- pub struct NoOpMutations;
- impl WriteMutations for NoOpMutations {
- fn append_children(&mut self, _: ElementId, _: usize) {}
- fn assign_node_id(&mut self, _: &'static [u8], _: ElementId) {}
- fn create_placeholder(&mut self, _: ElementId) {}
- fn create_text_node(&mut self, _: &str, _: ElementId) {}
- fn load_template(&mut self, _: Template, _: usize, _: ElementId) {}
- fn replace_node_with(&mut self, _: ElementId, _: usize) {}
- fn replace_placeholder_with_nodes(&mut self, _: &'static [u8], _: usize) {}
- fn insert_nodes_after(&mut self, _: ElementId, _: usize) {}
- fn insert_nodes_before(&mut self, _: ElementId, _: usize) {}
- fn set_attribute(
- &mut self,
- _: &'static str,
- _: Option<&'static str>,
- _: &AttributeValue,
- _: ElementId,
- ) {
- }
- fn set_node_text(&mut self, _: &str, _: ElementId) {}
- fn create_event_listener(&mut self, _: &'static str, _: ElementId) {}
- fn remove_event_listener(&mut self, _: &'static str, _: ElementId) {}
- fn remove_node(&mut self, _: ElementId) {}
- fn push_root(&mut self, _: ElementId) {}
- }
|