write_native_mutations.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. use crate::unified_bindings::Interpreter as Channel;
  2. use dioxus_core::{Template, TemplateAttribute, TemplateNode, WriteMutations};
  3. use dioxus_html::event_bubbles;
  4. use rustc_hash::FxHashMap;
  5. /// The state needed to apply mutations to a channel. This state should be kept across all mutations for the app
  6. #[derive(Default)]
  7. pub struct MutationState {
  8. /// The currently registered templates with the template ids
  9. templates: FxHashMap<Template, u16>,
  10. /// The channel that we are applying mutations to
  11. channel: Channel,
  12. }
  13. impl MutationState {
  14. pub fn new() -> Self {
  15. Self::default()
  16. }
  17. pub fn export_memory(&mut self) -> Vec<u8> {
  18. let bytes: Vec<_> = self.channel.export_memory().collect();
  19. self.channel.reset();
  20. bytes
  21. }
  22. pub fn write_memory_into(&mut self, buffer: &mut Vec<u8>) {
  23. buffer.extend(self.channel.export_memory());
  24. self.channel.reset();
  25. }
  26. pub fn channel(&mut self) -> &mut Channel {
  27. &mut self.channel
  28. }
  29. pub fn channel_mut(&mut self) -> &mut Channel {
  30. &mut self.channel
  31. }
  32. fn create_template_node(&mut self, node: &'static TemplateNode) {
  33. use TemplateNode::*;
  34. match node {
  35. Element {
  36. tag,
  37. namespace,
  38. attrs,
  39. children,
  40. ..
  41. } => {
  42. // Push the current node onto the stack
  43. match namespace {
  44. Some(ns) => self.channel.create_element_ns(tag, ns),
  45. None => self.channel.create_element(tag),
  46. }
  47. // Set attributes on the current node
  48. for attr in *attrs {
  49. if let TemplateAttribute::Static {
  50. name,
  51. value,
  52. namespace,
  53. } = attr
  54. {
  55. self.channel
  56. .set_top_attribute(name, value, namespace.unwrap_or_default())
  57. }
  58. }
  59. // Add each child to the stack
  60. for child in *children {
  61. self.create_template_node(child);
  62. }
  63. // Add all children to the parent
  64. self.channel.append_children_to_top(children.len() as u16);
  65. }
  66. Text { text } => self.channel.create_raw_text(text),
  67. Dynamic { .. } => self.channel.add_placeholder(),
  68. }
  69. }
  70. }
  71. impl WriteMutations for MutationState {
  72. fn append_children(&mut self, id: dioxus_core::ElementId, m: usize) {
  73. self.channel.append_children(id.0 as u32, m as u16);
  74. }
  75. fn assign_node_id(&mut self, path: &'static [u8], id: dioxus_core::ElementId) {
  76. self.channel.assign_id_ref(path, id.0 as u32);
  77. }
  78. fn create_placeholder(&mut self, id: dioxus_core::ElementId) {
  79. self.channel.create_placeholder(id.0 as u32);
  80. }
  81. fn create_text_node(&mut self, value: &str, id: dioxus_core::ElementId) {
  82. self.channel.create_text_node(value, id.0 as u32);
  83. }
  84. fn load_template(&mut self, template: Template, index: usize, id: dioxus_core::ElementId) {
  85. // Get the template or create it if we haven't seen it before
  86. let tmpl_id = self.templates.get(&template).cloned().unwrap_or_else(|| {
  87. let tmpl_id = self.templates.len() as u16;
  88. self.templates.insert(template, tmpl_id);
  89. for root in template.roots.iter() {
  90. self.create_template_node(root);
  91. }
  92. let len = template.roots.len() as u16;
  93. self.channel.add_templates(tmpl_id, len);
  94. tmpl_id
  95. });
  96. self.channel
  97. .load_template(tmpl_id, index as u16, id.0 as u32);
  98. }
  99. fn replace_node_with(&mut self, id: dioxus_core::ElementId, m: usize) {
  100. self.channel.replace_with(id.0 as u32, m as u16);
  101. }
  102. fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize) {
  103. self.channel.replace_placeholder_ref(path, m as u16);
  104. }
  105. fn insert_nodes_after(&mut self, id: dioxus_core::ElementId, m: usize) {
  106. self.channel.insert_after(id.0 as u32, m as u16);
  107. }
  108. fn insert_nodes_before(&mut self, id: dioxus_core::ElementId, m: usize) {
  109. self.channel.insert_before(id.0 as u32, m as u16);
  110. }
  111. fn set_attribute(
  112. &mut self,
  113. name: &'static str,
  114. ns: Option<&'static str>,
  115. value: &dioxus_core::AttributeValue,
  116. id: dioxus_core::ElementId,
  117. ) {
  118. match value {
  119. dioxus_core::AttributeValue::Text(txt) => {
  120. self.channel
  121. .set_attribute(id.0 as u32, name, txt, ns.unwrap_or_default())
  122. }
  123. dioxus_core::AttributeValue::Float(f) => self.channel.set_attribute(
  124. id.0 as u32,
  125. name,
  126. &f.to_string(),
  127. ns.unwrap_or_default(),
  128. ),
  129. dioxus_core::AttributeValue::Int(n) => self.channel.set_attribute(
  130. id.0 as u32,
  131. name,
  132. &n.to_string(),
  133. ns.unwrap_or_default(),
  134. ),
  135. dioxus_core::AttributeValue::Bool(b) => self.channel.set_attribute(
  136. id.0 as u32,
  137. name,
  138. if *b { "true" } else { "false" },
  139. ns.unwrap_or_default(),
  140. ),
  141. dioxus_core::AttributeValue::None => {
  142. self.channel
  143. .remove_attribute(id.0 as u32, name, ns.unwrap_or_default())
  144. }
  145. _ => unreachable!("Any attributes are not supported by the current renderer"),
  146. }
  147. }
  148. fn set_node_text(&mut self, value: &str, id: dioxus_core::ElementId) {
  149. self.channel.set_text(id.0 as u32, value);
  150. }
  151. fn create_event_listener(&mut self, name: &'static str, id: dioxus_core::ElementId) {
  152. // note that we use the foreign event listener here instead of the native one
  153. // the native method assumes we have direct access to the dom, which we don't.
  154. self.channel
  155. .foreign_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
  156. }
  157. fn remove_event_listener(&mut self, name: &'static str, id: dioxus_core::ElementId) {
  158. self.channel
  159. .remove_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
  160. }
  161. fn remove_node(&mut self, id: dioxus_core::ElementId) {
  162. self.channel.remove(id.0 as u32);
  163. }
  164. fn push_root(&mut self, id: dioxus_core::ElementId) {
  165. self.channel.push_root(id.0 as _);
  166. }
  167. }
  168. /// A synchronous response to a browser event which may prevent the default browser's action
  169. #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
  170. #[derive(Default)]
  171. pub struct SynchronousEventResponse {
  172. #[cfg(feature = "serialize")]
  173. #[serde(rename = "preventDefault")]
  174. prevent_default: bool,
  175. }
  176. impl SynchronousEventResponse {
  177. /// Create a new SynchronousEventResponse
  178. #[allow(unused)]
  179. pub fn new(prevent_default: bool) -> Self {
  180. Self {
  181. #[cfg(feature = "serialize")]
  182. prevent_default,
  183. }
  184. }
  185. }