nodes.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. use crate::{any_props::AnyProps, arena::ElementId, Element, ScopeId, ScopeState, UiEvent};
  2. use bumpalo::boxed::Box as BumpBox;
  3. use std::{
  4. any::{Any, TypeId},
  5. cell::{Cell, RefCell},
  6. };
  7. pub type TemplateId = &'static str;
  8. /// A reference to a template along with any context needed to hydrate it
  9. ///
  10. /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping
  11. /// static parts of the template.
  12. #[derive(Debug, Clone)]
  13. pub struct VNode<'a> {
  14. /// The key given to the root of this template.
  15. ///
  16. /// In fragments, this is the key of the first child. In other cases, it is the key of the root.
  17. pub key: Option<&'a str>,
  18. /// When rendered, this template will be linked to its parent manually
  19. pub parent: Option<ElementId>,
  20. /// The static nodes and static descriptor of the template
  21. pub template: Template<'static>,
  22. /// The IDs for the roots of this template - to be used when moving the template around and removing it from
  23. /// the actual Dom
  24. pub root_ids: &'a [Cell<ElementId>],
  25. /// The dynamic parts of the template
  26. pub dynamic_nodes: &'a [DynamicNode<'a>],
  27. /// The dynamic parts of the template
  28. pub dynamic_attrs: &'a [Attribute<'a>],
  29. }
  30. impl<'a> VNode<'a> {
  31. pub fn empty() -> Element<'a> {
  32. Ok(VNode {
  33. key: None,
  34. parent: None,
  35. root_ids: &[],
  36. dynamic_nodes: &[],
  37. dynamic_attrs: &[],
  38. template: Template {
  39. id: "dioxus-empty",
  40. roots: &[],
  41. node_paths: &[],
  42. attr_paths: &[],
  43. },
  44. })
  45. }
  46. pub fn dynamic_root(&self, idx: usize) -> Option<&'a DynamicNode<'a>> {
  47. match &self.template.roots[idx] {
  48. TemplateNode::Element { .. } | TemplateNode::Text(_) => None,
  49. TemplateNode::Dynamic(id) | TemplateNode::DynamicText(id) => {
  50. Some(&self.dynamic_nodes[*id])
  51. }
  52. }
  53. }
  54. }
  55. #[derive(Debug, Clone, Copy)]
  56. pub struct Template<'a> {
  57. pub id: &'a str,
  58. pub roots: &'a [TemplateNode<'a>],
  59. pub node_paths: &'a [&'a [u8]],
  60. pub attr_paths: &'a [&'a [u8]],
  61. }
  62. /// A weird-ish variant of VNodes with way more limited types
  63. #[derive(Debug, Clone, Copy)]
  64. pub enum TemplateNode<'a> {
  65. Element {
  66. tag: &'a str,
  67. namespace: Option<&'a str>,
  68. attrs: &'a [TemplateAttribute<'a>],
  69. children: &'a [TemplateNode<'a>],
  70. inner_opt: bool,
  71. },
  72. Text(&'a str),
  73. Dynamic(usize),
  74. DynamicText(usize),
  75. }
  76. #[derive(Debug)]
  77. pub enum DynamicNode<'a> {
  78. Component(VComponent<'a>),
  79. Text(VText<'a>),
  80. Fragment(VFragment<'a>),
  81. }
  82. impl<'a> DynamicNode<'a> {
  83. pub fn is_component(&self) -> bool {
  84. matches!(self, DynamicNode::Component(_))
  85. }
  86. }
  87. pub struct VComponent<'a> {
  88. pub name: &'static str,
  89. pub static_props: bool,
  90. pub scope: Cell<Option<ScopeId>>,
  91. pub render_fn: *const (),
  92. pub(crate) props: Cell<Option<Box<dyn AnyProps<'a> + 'a>>>,
  93. }
  94. impl<'a> std::fmt::Debug for VComponent<'a> {
  95. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  96. f.debug_struct("VComponent")
  97. .field("name", &self.name)
  98. .field("static_props", &self.static_props)
  99. .field("scope", &self.scope)
  100. .finish()
  101. }
  102. }
  103. #[derive(Debug)]
  104. pub struct VText<'a> {
  105. pub id: Cell<ElementId>,
  106. pub value: &'a str,
  107. }
  108. #[derive(Debug)]
  109. pub enum VFragment<'a> {
  110. Empty(Cell<ElementId>),
  111. NonEmpty(&'a [VNode<'a>]),
  112. }
  113. #[derive(Debug)]
  114. pub enum TemplateAttribute<'a> {
  115. Static {
  116. name: &'static str,
  117. value: &'a str,
  118. namespace: Option<&'static str>,
  119. volatile: bool,
  120. },
  121. Dynamic(usize),
  122. }
  123. #[derive(Debug)]
  124. pub struct Attribute<'a> {
  125. pub name: &'a str,
  126. pub value: AttributeValue<'a>,
  127. pub namespace: Option<&'static str>,
  128. pub mounted_element: Cell<ElementId>,
  129. pub volatile: bool,
  130. }
  131. pub enum AttributeValue<'a> {
  132. Text(&'a str),
  133. Float(f32),
  134. Int(i32),
  135. Bool(bool),
  136. Listener(RefCell<Option<ListenerCb<'a>>>),
  137. Any(BumpBox<'a, dyn AnyValue>),
  138. None,
  139. }
  140. type ListenerCb<'a> = BumpBox<'a, dyn FnMut(UiEvent<dyn Any>) + 'a>;
  141. impl<'a> AttributeValue<'a> {
  142. pub fn new_listener<T: 'static>(
  143. cx: &'a ScopeState,
  144. mut callback: impl FnMut(UiEvent<T>) + 'a,
  145. ) -> AttributeValue<'a> {
  146. let boxed: BumpBox<'a, dyn FnMut(_) + 'a> = unsafe {
  147. BumpBox::from_raw(cx.bump().alloc(move |event: UiEvent<dyn Any>| {
  148. if let Ok(data) = event.data.downcast::<T>() {
  149. callback(UiEvent {
  150. bubbles: event.bubbles,
  151. data,
  152. })
  153. }
  154. }))
  155. };
  156. AttributeValue::Listener(RefCell::new(Some(boxed)))
  157. }
  158. }
  159. impl<'a> std::fmt::Debug for AttributeValue<'a> {
  160. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  161. match self {
  162. Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
  163. Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
  164. Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
  165. Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
  166. Self::Listener(_) => f.debug_tuple("Listener").finish(),
  167. Self::Any(_) => f.debug_tuple("Any").finish(),
  168. Self::None => write!(f, "None"),
  169. }
  170. }
  171. }
  172. impl<'a> PartialEq for AttributeValue<'a> {
  173. fn eq(&self, other: &Self) -> bool {
  174. match (self, other) {
  175. (Self::Text(l0), Self::Text(r0)) => l0 == r0,
  176. (Self::Float(l0), Self::Float(r0)) => l0 == r0,
  177. (Self::Int(l0), Self::Int(r0)) => l0 == r0,
  178. (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
  179. (Self::Listener(_), Self::Listener(_)) => true,
  180. (Self::Any(l0), Self::Any(r0)) => l0.any_cmp(r0.as_ref()),
  181. _ => core::mem::discriminant(self) == core::mem::discriminant(other),
  182. }
  183. }
  184. }
  185. impl<'a> AttributeValue<'a> {
  186. pub fn matches_type(&self, other: &'a AttributeValue<'a>) -> bool {
  187. matches!(
  188. (self, other),
  189. (Self::Text(_), Self::Text(_))
  190. | (Self::Float(_), Self::Float(_))
  191. | (Self::Int(_), Self::Int(_))
  192. | (Self::Bool(_), Self::Bool(_))
  193. | (Self::Listener(_), Self::Listener(_))
  194. | (Self::Any(_), Self::Any(_))
  195. )
  196. }
  197. }
  198. pub trait AnyValue {
  199. fn any_cmp(&self, other: &dyn AnyValue) -> bool;
  200. fn our_typeid(&self) -> TypeId;
  201. }
  202. impl<T: PartialEq + Any> AnyValue for T {
  203. fn any_cmp(&self, other: &dyn AnyValue) -> bool {
  204. if self.type_id() != other.our_typeid() {
  205. return false;
  206. }
  207. self == unsafe { &*(other as *const _ as *const T) }
  208. }
  209. fn our_typeid(&self) -> TypeId {
  210. self.type_id()
  211. }
  212. }
  213. #[test]
  214. fn what_are_the_sizes() {
  215. dbg!(std::mem::size_of::<VNode>());
  216. dbg!(std::mem::size_of::<Template>());
  217. dbg!(std::mem::size_of::<TemplateNode>());
  218. }