nodes.rs 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. use dioxus_core_types::DioxusFormattable;
  2. use crate::events::ListenerCallback;
  3. use crate::innerlude::VProps;
  4. use crate::prelude::RenderError;
  5. use crate::{any_props::BoxedAnyProps, innerlude::ScopeState};
  6. use crate::{arena::ElementId, Element, Event};
  7. use crate::{
  8. innerlude::{ElementRef, MountId},
  9. properties::ComponentFunction,
  10. };
  11. use crate::{Properties, ScopeId, VirtualDom};
  12. use std::ops::Deref;
  13. use std::rc::Rc;
  14. use std::vec;
  15. use std::{
  16. any::{Any, TypeId},
  17. cell::Cell,
  18. fmt::{Arguments, Debug},
  19. };
  20. /// The information about the
  21. #[derive(Debug)]
  22. pub(crate) struct VNodeMount {
  23. /// The parent of this node
  24. pub parent: Option<ElementRef>,
  25. /// A back link to the original node
  26. pub node: VNode,
  27. /// The IDs for the roots of this template - to be used when moving the template around and removing it from
  28. /// the actual Dom
  29. pub root_ids: Box<[ElementId]>,
  30. /// The element in the DOM that each attribute is mounted to
  31. pub(crate) mounted_attributes: Box<[ElementId]>,
  32. /// For components: This is the ScopeId the component is mounted to
  33. /// For other dynamic nodes: This is element in the DOM that each dynamic node is mounted to
  34. pub(crate) mounted_dynamic_nodes: Box<[usize]>,
  35. }
  36. /// A reference to a template along with any context needed to hydrate it
  37. ///
  38. /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping
  39. /// static parts of the template.
  40. #[derive(Debug)]
  41. pub struct VNodeInner {
  42. /// The key given to the root of this template.
  43. ///
  44. /// In fragments, this is the key of the first child. In other cases, it is the key of the root.
  45. pub key: Option<String>,
  46. /// The static nodes and static descriptor of the template
  47. pub template: Template,
  48. /// The dynamic nodes in the template
  49. pub dynamic_nodes: Box<[DynamicNode]>,
  50. /// The dynamic attribute slots in the template
  51. ///
  52. /// This is a list of positions in the template where dynamic attributes can be inserted.
  53. ///
  54. /// The inner list *must* be in the format [static named attributes, remaining dynamically named attributes].
  55. ///
  56. /// For example:
  57. /// ```rust
  58. /// # use dioxus::prelude::*;
  59. /// let class = "my-class";
  60. /// let attrs = vec![];
  61. /// let color = "red";
  62. ///
  63. /// rsx! {
  64. /// div {
  65. /// class: "{class}",
  66. /// ..attrs,
  67. /// p {
  68. /// color: "{color}",
  69. /// }
  70. /// }
  71. /// };
  72. /// ```
  73. ///
  74. /// Would be represented as:
  75. /// ```text
  76. /// [
  77. /// [class, every attribute in attrs sorted by name], // Slot 0 in the template
  78. /// [color], // Slot 1 in the template
  79. /// ]
  80. /// ```
  81. pub dynamic_attrs: Box<[Box<[Attribute]>]>,
  82. }
  83. /// A reference to a template along with any context needed to hydrate it
  84. ///
  85. /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping
  86. /// static parts of the template.
  87. #[derive(Debug, Clone)]
  88. pub struct VNode {
  89. vnode: Rc<VNodeInner>,
  90. /// The mount information for this template
  91. pub(crate) mount: Cell<MountId>,
  92. }
  93. impl AsRef<VNode> for Element {
  94. fn as_ref(&self) -> &VNode {
  95. match self {
  96. Element::Ok(node) => node,
  97. Element::Err(RenderError::Aborted(err)) => &err.render,
  98. Element::Err(RenderError::Suspended(fut)) => &fut.placeholder,
  99. }
  100. }
  101. }
  102. impl From<&Element> for VNode {
  103. fn from(val: &Element) -> Self {
  104. AsRef::as_ref(val).clone()
  105. }
  106. }
  107. impl From<Element> for VNode {
  108. fn from(val: Element) -> Self {
  109. match val {
  110. Element::Ok(node) => node,
  111. Element::Err(RenderError::Aborted(err)) => err.render,
  112. Element::Err(RenderError::Suspended(fut)) => fut.placeholder,
  113. }
  114. }
  115. }
  116. /// A tiny helper trait to get the vnode for a Element
  117. pub(crate) trait AsVNode {
  118. /// Get the vnode for this element
  119. fn as_vnode(&self) -> &VNode;
  120. /// Create a deep clone of this VNode
  121. fn deep_clone(&self) -> Self;
  122. }
  123. impl AsVNode for Element {
  124. fn as_vnode(&self) -> &VNode {
  125. AsRef::as_ref(self)
  126. }
  127. fn deep_clone(&self) -> Self {
  128. match self {
  129. Ok(node) => Ok(node.deep_clone()),
  130. Err(RenderError::Aborted(err)) => Err(RenderError::Aborted(err.deep_clone())),
  131. Err(RenderError::Suspended(fut)) => Err(RenderError::Suspended(fut.deep_clone())),
  132. }
  133. }
  134. }
  135. impl Default for VNode {
  136. fn default() -> Self {
  137. Self::placeholder()
  138. }
  139. }
  140. impl PartialEq for VNode {
  141. fn eq(&self, other: &Self) -> bool {
  142. Rc::ptr_eq(&self.vnode, &other.vnode)
  143. }
  144. }
  145. impl Deref for VNode {
  146. type Target = VNodeInner;
  147. fn deref(&self) -> &Self::Target {
  148. &self.vnode
  149. }
  150. }
  151. impl VNode {
  152. /// Create a template with no nodes that will be skipped over during diffing
  153. pub fn empty() -> Element {
  154. Ok(Self::default())
  155. }
  156. /// Create a template with a single placeholder node
  157. pub fn placeholder() -> Self {
  158. use std::cell::OnceCell;
  159. // We can reuse all placeholders across the same thread to save memory
  160. thread_local! {
  161. static PLACEHOLDER_VNODE: OnceCell<Rc<VNodeInner>> = const { OnceCell::new() };
  162. }
  163. let vnode = PLACEHOLDER_VNODE.with(|cell| {
  164. cell.get_or_init(move || {
  165. Rc::new(VNodeInner {
  166. key: None,
  167. dynamic_nodes: Box::new([DynamicNode::Placeholder(Default::default())]),
  168. dynamic_attrs: Box::new([]),
  169. template: Template {
  170. roots: &[TemplateNode::Dynamic { id: 0 }],
  171. node_paths: &[&[0]],
  172. attr_paths: &[],
  173. },
  174. })
  175. })
  176. .clone()
  177. });
  178. Self {
  179. vnode,
  180. mount: Default::default(),
  181. }
  182. }
  183. /// Create a new VNode
  184. pub fn new(
  185. key: Option<String>,
  186. template: Template,
  187. dynamic_nodes: Box<[DynamicNode]>,
  188. dynamic_attrs: Box<[Box<[Attribute]>]>,
  189. ) -> Self {
  190. Self {
  191. vnode: Rc::new(VNodeInner {
  192. key,
  193. template,
  194. dynamic_nodes,
  195. dynamic_attrs,
  196. }),
  197. mount: Default::default(),
  198. }
  199. }
  200. /// Load a dynamic root at the given index
  201. ///
  202. /// Returns [`None`] if the root is actually a static node (Element/Text)
  203. pub fn dynamic_root(&self, idx: usize) -> Option<&DynamicNode> {
  204. self.template.roots[idx]
  205. .dynamic_id()
  206. .map(|id| &self.dynamic_nodes[id])
  207. }
  208. /// Get the mounted id for a dynamic node index
  209. pub fn mounted_dynamic_node(
  210. &self,
  211. dynamic_node_idx: usize,
  212. dom: &VirtualDom,
  213. ) -> Option<ElementId> {
  214. let mount = self.mount.get().as_usize()?;
  215. match &self.dynamic_nodes[dynamic_node_idx] {
  216. DynamicNode::Text(_) | DynamicNode::Placeholder(_) => {
  217. let mounts = dom.runtime.mounts.borrow();
  218. mounts
  219. .get(mount)?
  220. .mounted_dynamic_nodes
  221. .get(dynamic_node_idx)
  222. .map(|id| ElementId(*id))
  223. }
  224. _ => None,
  225. }
  226. }
  227. /// Get the mounted id for a root node index
  228. pub fn mounted_root(&self, root_idx: usize, dom: &VirtualDom) -> Option<ElementId> {
  229. let mount = self.mount.get().as_usize()?;
  230. let mounts = dom.runtime.mounts.borrow();
  231. mounts.get(mount)?.root_ids.get(root_idx).copied()
  232. }
  233. /// Get the mounted id for a dynamic attribute index
  234. pub fn mounted_dynamic_attribute(
  235. &self,
  236. dynamic_attribute_idx: usize,
  237. dom: &VirtualDom,
  238. ) -> Option<ElementId> {
  239. let mount = self.mount.get().as_usize()?;
  240. let mounts = dom.runtime.mounts.borrow();
  241. mounts
  242. .get(mount)?
  243. .mounted_attributes
  244. .get(dynamic_attribute_idx)
  245. .copied()
  246. }
  247. /// Create a deep clone of this VNode
  248. pub(crate) fn deep_clone(&self) -> Self {
  249. Self {
  250. vnode: Rc::new(VNodeInner {
  251. key: self.vnode.key.clone(),
  252. template: self.vnode.template,
  253. dynamic_nodes: self
  254. .vnode
  255. .dynamic_nodes
  256. .iter()
  257. .map(|node| match node {
  258. DynamicNode::Fragment(nodes) => DynamicNode::Fragment(
  259. nodes.iter().map(|node| node.deep_clone()).collect(),
  260. ),
  261. other => other.clone(),
  262. })
  263. .collect(),
  264. dynamic_attrs: self
  265. .vnode
  266. .dynamic_attrs
  267. .iter()
  268. .map(|attr| {
  269. attr.iter()
  270. .map(|attribute| attribute.deep_clone())
  271. .collect()
  272. })
  273. .collect(),
  274. }),
  275. mount: Default::default(),
  276. }
  277. }
  278. }
  279. type StaticStr = &'static str;
  280. type StaticPathArray = &'static [&'static [u8]];
  281. type StaticTemplateArray = &'static [TemplateNode];
  282. type StaticTemplateAttributeArray = &'static [TemplateAttribute];
  283. /// A static layout of a UI tree that describes a set of dynamic and static nodes.
  284. ///
  285. /// This is the core innovation in Dioxus. Most UIs are made of static nodes, yet participate in diffing like any
  286. /// dynamic node. This struct can be created at compile time. It promises that its pointer is unique, allow Dioxus to use
  287. /// its static description of the UI to skip immediately to the dynamic nodes during diffing.
  288. #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
  289. #[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord)]
  290. pub struct Template {
  291. /// The list of template nodes that make up the template
  292. ///
  293. /// Unlike react, calls to `rsx!` can have multiple roots. This list supports that paradigm.
  294. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
  295. pub roots: StaticTemplateArray,
  296. /// The paths of each node relative to the root of the template.
  297. ///
  298. /// These will be one segment shorter than the path sent to the renderer since those paths are relative to the
  299. /// topmost element, not the `roots` field.
  300. #[cfg_attr(
  301. feature = "serialize",
  302. serde(deserialize_with = "deserialize_bytes_leaky")
  303. )]
  304. pub node_paths: StaticPathArray,
  305. /// The paths of each dynamic attribute relative to the root of the template
  306. ///
  307. /// These will be one segment shorter than the path sent to the renderer since those paths are relative to the
  308. /// topmost element, not the `roots` field.
  309. #[cfg_attr(
  310. feature = "serialize",
  311. serde(deserialize_with = "deserialize_bytes_leaky", bound = "")
  312. )]
  313. pub attr_paths: StaticPathArray,
  314. }
  315. // Are identical static items merged in the current build. Rust doesn't have a cfg(merge_statics) attribute
  316. // so we have to check this manually
  317. #[allow(unpredictable_function_pointer_comparisons)] // This attribute should be removed once MSRV is 1.85 or greater and the below change is made
  318. fn static_items_merged() -> bool {
  319. fn a() {}
  320. fn b() {}
  321. a as fn() == b as fn()
  322. // std::ptr::fn_addr_eq(a as fn(), b as fn()) <<<<---- This should replace the a as fn() === b as fn() once the MSRV is 1.85 or greater
  323. }
  324. impl std::hash::Hash for Template {
  325. fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
  326. // If identical static items are merged, we can compare templates by pointer
  327. if static_items_merged() {
  328. std::ptr::hash(self.roots as *const _, state);
  329. std::ptr::hash(self.node_paths as *const _, state);
  330. std::ptr::hash(self.attr_paths as *const _, state);
  331. }
  332. // Otherwise, we hash by value
  333. else {
  334. self.roots.hash(state);
  335. self.node_paths.hash(state);
  336. self.attr_paths.hash(state);
  337. }
  338. }
  339. }
  340. impl PartialEq for Template {
  341. fn eq(&self, other: &Self) -> bool {
  342. // If identical static items are merged, we can compare templates by pointer
  343. if static_items_merged() {
  344. std::ptr::eq(self.roots as *const _, other.roots as *const _)
  345. && std::ptr::eq(self.node_paths as *const _, other.node_paths as *const _)
  346. && std::ptr::eq(self.attr_paths as *const _, other.attr_paths as *const _)
  347. }
  348. // Otherwise, we compare by value
  349. else {
  350. self.roots == other.roots
  351. && self.node_paths == other.node_paths
  352. && self.attr_paths == other.attr_paths
  353. }
  354. }
  355. }
  356. #[cfg(feature = "serialize")]
  357. pub(crate) fn deserialize_string_leaky<'a, 'de, D>(
  358. deserializer: D,
  359. ) -> Result<&'static str, D::Error>
  360. where
  361. D: serde::Deserializer<'de>,
  362. {
  363. use serde::Deserialize;
  364. let deserialized = String::deserialize(deserializer)?;
  365. Ok(&*Box::leak(deserialized.into_boxed_str()))
  366. }
  367. #[cfg(feature = "serialize")]
  368. fn deserialize_bytes_leaky<'a, 'de, D>(
  369. deserializer: D,
  370. ) -> Result<&'static [&'static [u8]], D::Error>
  371. where
  372. D: serde::Deserializer<'de>,
  373. {
  374. use serde::Deserialize;
  375. let deserialized = Vec::<Vec<u8>>::deserialize(deserializer)?;
  376. let deserialized = deserialized
  377. .into_iter()
  378. .map(|v| &*Box::leak(v.into_boxed_slice()))
  379. .collect::<Vec<_>>();
  380. Ok(&*Box::leak(deserialized.into_boxed_slice()))
  381. }
  382. #[cfg(feature = "serialize")]
  383. pub(crate) fn deserialize_leaky<'a, 'de, T, D>(deserializer: D) -> Result<&'static [T], D::Error>
  384. where
  385. T: serde::Deserialize<'de>,
  386. D: serde::Deserializer<'de>,
  387. {
  388. use serde::Deserialize;
  389. let deserialized = Box::<[T]>::deserialize(deserializer)?;
  390. Ok(&*Box::leak(deserialized))
  391. }
  392. #[cfg(feature = "serialize")]
  393. pub(crate) fn deserialize_option_leaky<'a, 'de, D>(
  394. deserializer: D,
  395. ) -> Result<Option<&'static str>, D::Error>
  396. where
  397. D: serde::Deserializer<'de>,
  398. {
  399. use serde::Deserialize;
  400. let deserialized = Option::<String>::deserialize(deserializer)?;
  401. Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
  402. }
  403. impl Template {
  404. /// Is this template worth caching at all, since it's completely runtime?
  405. ///
  406. /// There's no point in saving templates that are completely dynamic, since they'll be recreated every time anyway.
  407. pub fn is_completely_dynamic(&self) -> bool {
  408. use TemplateNode::*;
  409. self.roots.iter().all(|root| matches!(root, Dynamic { .. }))
  410. }
  411. }
  412. /// A statically known node in a layout.
  413. ///
  414. /// This can be created at compile time, saving the VirtualDom time when diffing the tree
  415. #[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
  416. #[cfg_attr(
  417. feature = "serialize",
  418. derive(serde::Serialize, serde::Deserialize),
  419. serde(tag = "type")
  420. )]
  421. pub enum TemplateNode {
  422. /// An statically known element in the dom.
  423. ///
  424. /// In HTML this would be something like `<div id="123"> </div>`
  425. Element {
  426. /// The name of the element
  427. ///
  428. /// IE for a div, it would be the string "div"
  429. #[cfg_attr(
  430. feature = "serialize",
  431. serde(deserialize_with = "deserialize_string_leaky")
  432. )]
  433. tag: StaticStr,
  434. /// The namespace of the element
  435. ///
  436. /// In HTML, this would be a valid URI that defines a namespace for all elements below it
  437. /// SVG is an example of this namespace
  438. #[cfg_attr(
  439. feature = "serialize",
  440. serde(deserialize_with = "deserialize_option_leaky")
  441. )]
  442. namespace: Option<StaticStr>,
  443. /// A list of possibly dynamic attributes for this element
  444. ///
  445. /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`.
  446. #[cfg_attr(
  447. feature = "serialize",
  448. serde(deserialize_with = "deserialize_leaky", bound = "")
  449. )]
  450. attrs: StaticTemplateAttributeArray,
  451. /// A list of template nodes that define another set of template nodes
  452. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
  453. children: StaticTemplateArray,
  454. },
  455. /// This template node is just a piece of static text
  456. Text {
  457. /// The actual text
  458. #[cfg_attr(
  459. feature = "serialize",
  460. serde(deserialize_with = "deserialize_string_leaky", bound = "")
  461. )]
  462. text: StaticStr,
  463. },
  464. /// This template node is unknown, and needs to be created at runtime.
  465. Dynamic {
  466. /// The index of the dynamic node in the VNode's dynamic_nodes list
  467. id: usize,
  468. },
  469. }
  470. impl TemplateNode {
  471. /// Try to load the dynamic node at the given index
  472. pub fn dynamic_id(&self) -> Option<usize> {
  473. use TemplateNode::*;
  474. match self {
  475. Dynamic { id } => Some(*id),
  476. _ => None,
  477. }
  478. }
  479. }
  480. /// A node created at runtime
  481. ///
  482. /// This node's index in the DynamicNode list on VNode should match its respective `Dynamic` index
  483. #[derive(Debug, Clone)]
  484. pub enum DynamicNode {
  485. /// A component node
  486. ///
  487. /// Most of the time, Dioxus will actually know which component this is as compile time, but the props and
  488. /// assigned scope are dynamic.
  489. ///
  490. /// The actual VComponent can be dynamic between two VNodes, though, allowing implementations to swap
  491. /// the render function at runtime
  492. Component(VComponent),
  493. /// A text node
  494. Text(VText),
  495. /// A placeholder
  496. ///
  497. /// Used by suspense when a node isn't ready and by fragments that don't render anything
  498. ///
  499. /// In code, this is just an ElementId whose initial value is set to 0 upon creation
  500. Placeholder(VPlaceholder),
  501. /// A list of VNodes.
  502. ///
  503. /// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering
  504. /// or iterators.
  505. Fragment(Vec<VNode>),
  506. }
  507. impl DynamicNode {
  508. /// Convert any item that implements [`IntoDynNode`] into a [`DynamicNode`]
  509. pub fn make_node<'c, I>(into: impl IntoDynNode<I> + 'c) -> DynamicNode {
  510. into.into_dyn_node()
  511. }
  512. }
  513. impl Default for DynamicNode {
  514. fn default() -> Self {
  515. Self::Placeholder(Default::default())
  516. }
  517. }
  518. /// An instance of a child component
  519. pub struct VComponent {
  520. /// The name of this component
  521. pub name: &'static str,
  522. /// The raw pointer to the render function
  523. pub(crate) render_fn: usize,
  524. /// The props for this component
  525. pub(crate) props: BoxedAnyProps,
  526. }
  527. impl Clone for VComponent {
  528. fn clone(&self) -> Self {
  529. Self {
  530. name: self.name,
  531. props: self.props.duplicate(),
  532. render_fn: self.render_fn,
  533. }
  534. }
  535. }
  536. impl VComponent {
  537. /// Create a new [`VComponent`] variant
  538. pub fn new<P, M: 'static>(
  539. component: impl ComponentFunction<P, M>,
  540. props: P,
  541. fn_name: &'static str,
  542. ) -> Self
  543. where
  544. P: Properties + 'static,
  545. {
  546. let render_fn = component.fn_ptr();
  547. let props = Box::new(VProps::new(
  548. component,
  549. <P as Properties>::memoize,
  550. props,
  551. fn_name,
  552. ));
  553. VComponent {
  554. render_fn,
  555. name: fn_name,
  556. props,
  557. }
  558. }
  559. /// Get the [`ScopeId`] this node is mounted to if it's mounted
  560. ///
  561. /// This is useful for rendering nodes outside of the VirtualDom, such as in SSR
  562. ///
  563. /// Returns [`None`] if the node is not mounted
  564. pub fn mounted_scope_id(
  565. &self,
  566. dynamic_node_index: usize,
  567. vnode: &VNode,
  568. dom: &VirtualDom,
  569. ) -> Option<ScopeId> {
  570. let mount = vnode.mount.get().as_usize()?;
  571. let mounts = dom.runtime.mounts.borrow();
  572. let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
  573. Some(ScopeId(scope_id))
  574. }
  575. /// Get the scope this node is mounted to if it's mounted
  576. ///
  577. /// This is useful for rendering nodes outside of the VirtualDom, such as in SSR
  578. ///
  579. /// Returns [`None`] if the node is not mounted
  580. pub fn mounted_scope<'a>(
  581. &self,
  582. dynamic_node_index: usize,
  583. vnode: &VNode,
  584. dom: &'a VirtualDom,
  585. ) -> Option<&'a ScopeState> {
  586. let mount = vnode.mount.get().as_usize()?;
  587. let mounts = dom.runtime.mounts.borrow();
  588. let scope_id = mounts.get(mount)?.mounted_dynamic_nodes[dynamic_node_index];
  589. dom.scopes.get(scope_id)
  590. }
  591. }
  592. impl std::fmt::Debug for VComponent {
  593. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  594. f.debug_struct("VComponent")
  595. .field("name", &self.name)
  596. .finish()
  597. }
  598. }
  599. /// A text node
  600. #[derive(Clone, Debug)]
  601. pub struct VText {
  602. /// The actual text itself
  603. pub value: String,
  604. }
  605. impl VText {
  606. /// Create a new VText
  607. pub fn new(value: impl ToString) -> Self {
  608. Self {
  609. value: value.to_string(),
  610. }
  611. }
  612. }
  613. impl From<Arguments<'_>> for VText {
  614. fn from(args: Arguments) -> Self {
  615. Self::new(args.to_string())
  616. }
  617. }
  618. /// A placeholder node, used by suspense and fragments
  619. #[derive(Clone, Debug, Default)]
  620. #[non_exhaustive]
  621. pub struct VPlaceholder {}
  622. /// An attribute of the TemplateNode, created at compile time
  623. #[derive(Debug, PartialEq, Hash, Eq, PartialOrd, Ord)]
  624. #[cfg_attr(
  625. feature = "serialize",
  626. derive(serde::Serialize, serde::Deserialize),
  627. serde(tag = "type")
  628. )]
  629. pub enum TemplateAttribute {
  630. /// This attribute is entirely known at compile time, enabling
  631. Static {
  632. /// The name of this attribute.
  633. ///
  634. /// For example, the `href` attribute in `href="https://example.com"`, would have the name "href"
  635. #[cfg_attr(
  636. feature = "serialize",
  637. serde(deserialize_with = "deserialize_string_leaky", bound = "")
  638. )]
  639. name: StaticStr,
  640. /// The value of this attribute, known at compile time
  641. ///
  642. /// Currently this only accepts &str, so values, even if they're known at compile time, are not known
  643. #[cfg_attr(
  644. feature = "serialize",
  645. serde(deserialize_with = "deserialize_string_leaky", bound = "")
  646. )]
  647. value: StaticStr,
  648. /// The namespace of this attribute. Does not exist in the HTML spec
  649. #[cfg_attr(
  650. feature = "serialize",
  651. serde(deserialize_with = "deserialize_option_leaky", bound = "")
  652. )]
  653. namespace: Option<StaticStr>,
  654. },
  655. /// The attribute in this position is actually determined dynamically at runtime
  656. ///
  657. /// This is the index into the dynamic_attributes field on the container VNode
  658. Dynamic {
  659. /// The index
  660. id: usize,
  661. },
  662. }
  663. /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`
  664. #[derive(Debug, Clone, PartialEq)]
  665. pub struct Attribute {
  666. /// The name of the attribute.
  667. pub name: &'static str,
  668. /// The value of the attribute
  669. pub value: AttributeValue,
  670. /// The namespace of the attribute.
  671. ///
  672. /// Doesn’t exist in the html spec. Used in Dioxus to denote “style” tags and other attribute groups.
  673. pub namespace: Option<&'static str>,
  674. /// An indication of we should always try and set the attribute. Used in controlled components to ensure changes are propagated
  675. pub volatile: bool,
  676. }
  677. impl Attribute {
  678. /// Create a new [`Attribute`] from a name, value, namespace, and volatile bool
  679. ///
  680. /// "Volatile" refers to whether or not Dioxus should always override the value. This helps prevent the UI in
  681. /// some renderers stay in sync with the VirtualDom's understanding of the world
  682. pub fn new<T>(
  683. name: &'static str,
  684. value: impl IntoAttributeValue<T>,
  685. namespace: Option<&'static str>,
  686. volatile: bool,
  687. ) -> Attribute {
  688. Attribute {
  689. name,
  690. namespace,
  691. volatile,
  692. value: value.into_value(),
  693. }
  694. }
  695. /// Create a new deep clone of this attribute
  696. pub(crate) fn deep_clone(&self) -> Self {
  697. Attribute {
  698. name: self.name,
  699. namespace: self.namespace,
  700. volatile: self.volatile,
  701. value: self.value.clone(),
  702. }
  703. }
  704. }
  705. /// Any of the built-in values that the Dioxus VirtualDom supports as dynamic attributes on elements
  706. ///
  707. /// These are built-in to be faster during the diffing process. To use a custom value, use the [`AttributeValue::Any`]
  708. /// variant.
  709. #[derive(Clone)]
  710. pub enum AttributeValue {
  711. /// Text attribute
  712. Text(String),
  713. /// A float
  714. Float(f64),
  715. /// Signed integer
  716. Int(i64),
  717. /// Boolean
  718. Bool(bool),
  719. /// A listener, like "onclick"
  720. Listener(ListenerCallback),
  721. /// An arbitrary value that implements PartialEq and is static
  722. Any(Rc<dyn AnyValue>),
  723. /// A "none" value, resulting in the removal of an attribute from the dom
  724. None,
  725. }
  726. impl AttributeValue {
  727. /// Create a new [`AttributeValue`] with the listener variant from a callback
  728. ///
  729. /// The callback must be confined to the lifetime of the ScopeState
  730. pub fn listener<T: 'static>(callback: impl FnMut(Event<T>) + 'static) -> AttributeValue {
  731. AttributeValue::Listener(ListenerCallback::new(callback).erase())
  732. }
  733. /// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
  734. pub fn any_value<T: AnyValue>(value: T) -> AttributeValue {
  735. AttributeValue::Any(Rc::new(value))
  736. }
  737. }
  738. impl std::fmt::Debug for AttributeValue {
  739. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  740. match self {
  741. Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
  742. Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
  743. Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
  744. Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
  745. Self::Listener(_) => f.debug_tuple("Listener").finish(),
  746. Self::Any(_) => f.debug_tuple("Any").finish(),
  747. Self::None => write!(f, "None"),
  748. }
  749. }
  750. }
  751. impl PartialEq for AttributeValue {
  752. fn eq(&self, other: &Self) -> bool {
  753. match (self, other) {
  754. (Self::Text(l0), Self::Text(r0)) => l0 == r0,
  755. (Self::Float(l0), Self::Float(r0)) => l0 == r0,
  756. (Self::Int(l0), Self::Int(r0)) => l0 == r0,
  757. (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
  758. (Self::Listener(l0), Self::Listener(r0)) => l0 == r0,
  759. (Self::Any(l0), Self::Any(r0)) => l0.as_ref().any_cmp(r0.as_ref()),
  760. (Self::None, Self::None) => true,
  761. _ => false,
  762. }
  763. }
  764. }
  765. #[doc(hidden)]
  766. pub trait AnyValue: 'static {
  767. fn any_cmp(&self, other: &dyn AnyValue) -> bool;
  768. fn as_any(&self) -> &dyn Any;
  769. fn type_id(&self) -> TypeId {
  770. self.as_any().type_id()
  771. }
  772. }
  773. impl<T: Any + PartialEq + 'static> AnyValue for T {
  774. fn any_cmp(&self, other: &dyn AnyValue) -> bool {
  775. if let Some(other) = other.as_any().downcast_ref() {
  776. self == other
  777. } else {
  778. false
  779. }
  780. }
  781. fn as_any(&self) -> &dyn Any {
  782. self
  783. }
  784. }
  785. /// A trait that allows various items to be converted into a dynamic node for the rsx macro
  786. pub trait IntoDynNode<A = ()> {
  787. /// Consume this item and produce a DynamicNode
  788. fn into_dyn_node(self) -> DynamicNode;
  789. }
  790. impl IntoDynNode for () {
  791. fn into_dyn_node(self) -> DynamicNode {
  792. DynamicNode::default()
  793. }
  794. }
  795. impl IntoDynNode for VNode {
  796. fn into_dyn_node(self) -> DynamicNode {
  797. DynamicNode::Fragment(vec![self])
  798. }
  799. }
  800. impl IntoDynNode for DynamicNode {
  801. fn into_dyn_node(self) -> DynamicNode {
  802. self
  803. }
  804. }
  805. impl<T: IntoDynNode> IntoDynNode for Option<T> {
  806. fn into_dyn_node(self) -> DynamicNode {
  807. match self {
  808. Some(val) => val.into_dyn_node(),
  809. None => DynamicNode::default(),
  810. }
  811. }
  812. }
  813. impl IntoDynNode for &Element {
  814. fn into_dyn_node(self) -> DynamicNode {
  815. match self.as_ref() {
  816. Ok(val) => val.into_dyn_node(),
  817. _ => DynamicNode::default(),
  818. }
  819. }
  820. }
  821. impl IntoDynNode for Element {
  822. fn into_dyn_node(self) -> DynamicNode {
  823. match self {
  824. Ok(val) => val.into_dyn_node(),
  825. _ => DynamicNode::default(),
  826. }
  827. }
  828. }
  829. impl IntoDynNode for &Option<VNode> {
  830. fn into_dyn_node(self) -> DynamicNode {
  831. match self.as_ref() {
  832. Some(val) => val.clone().into_dyn_node(),
  833. _ => DynamicNode::default(),
  834. }
  835. }
  836. }
  837. impl IntoDynNode for &str {
  838. fn into_dyn_node(self) -> DynamicNode {
  839. DynamicNode::Text(VText {
  840. value: self.to_string(),
  841. })
  842. }
  843. }
  844. impl IntoDynNode for String {
  845. fn into_dyn_node(self) -> DynamicNode {
  846. DynamicNode::Text(VText { value: self })
  847. }
  848. }
  849. impl IntoDynNode for Arguments<'_> {
  850. fn into_dyn_node(self) -> DynamicNode {
  851. DynamicNode::Text(VText {
  852. value: self.to_string(),
  853. })
  854. }
  855. }
  856. impl IntoDynNode for &VNode {
  857. fn into_dyn_node(self) -> DynamicNode {
  858. DynamicNode::Fragment(vec![self.clone()])
  859. }
  860. }
  861. pub trait IntoVNode {
  862. fn into_vnode(self) -> VNode;
  863. }
  864. impl IntoVNode for VNode {
  865. fn into_vnode(self) -> VNode {
  866. self
  867. }
  868. }
  869. impl IntoVNode for &VNode {
  870. fn into_vnode(self) -> VNode {
  871. self.clone()
  872. }
  873. }
  874. impl IntoVNode for Element {
  875. fn into_vnode(self) -> VNode {
  876. match self {
  877. Ok(val) => val.into_vnode(),
  878. _ => VNode::empty().unwrap(),
  879. }
  880. }
  881. }
  882. impl IntoVNode for &Element {
  883. fn into_vnode(self) -> VNode {
  884. match self {
  885. Ok(val) => val.into_vnode(),
  886. _ => VNode::empty().unwrap(),
  887. }
  888. }
  889. }
  890. impl IntoVNode for Option<VNode> {
  891. fn into_vnode(self) -> VNode {
  892. match self {
  893. Some(val) => val.into_vnode(),
  894. _ => VNode::empty().unwrap(),
  895. }
  896. }
  897. }
  898. impl IntoVNode for &Option<VNode> {
  899. fn into_vnode(self) -> VNode {
  900. match self.as_ref() {
  901. Some(val) => val.clone().into_vnode(),
  902. _ => VNode::empty().unwrap(),
  903. }
  904. }
  905. }
  906. impl IntoVNode for Option<Element> {
  907. fn into_vnode(self) -> VNode {
  908. match self {
  909. Some(val) => val.into_vnode(),
  910. _ => VNode::empty().unwrap(),
  911. }
  912. }
  913. }
  914. impl IntoVNode for &Option<Element> {
  915. fn into_vnode(self) -> VNode {
  916. match self.as_ref() {
  917. Some(val) => val.clone().into_vnode(),
  918. _ => VNode::empty().unwrap(),
  919. }
  920. }
  921. }
  922. // Note that we're using the E as a generic but this is never crafted anyways.
  923. pub struct FromNodeIterator;
  924. impl<T, I> IntoDynNode<FromNodeIterator> for T
  925. where
  926. T: Iterator<Item = I>,
  927. I: IntoVNode,
  928. {
  929. fn into_dyn_node(self) -> DynamicNode {
  930. let children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
  931. if children.is_empty() {
  932. DynamicNode::default()
  933. } else {
  934. DynamicNode::Fragment(children)
  935. }
  936. }
  937. }
  938. /// A value that can be converted into an attribute value
  939. pub trait IntoAttributeValue<T = ()> {
  940. /// Convert into an attribute value
  941. fn into_value(self) -> AttributeValue;
  942. }
  943. impl IntoAttributeValue for AttributeValue {
  944. fn into_value(self) -> AttributeValue {
  945. self
  946. }
  947. }
  948. impl IntoAttributeValue for &str {
  949. fn into_value(self) -> AttributeValue {
  950. AttributeValue::Text(self.to_string())
  951. }
  952. }
  953. impl IntoAttributeValue for String {
  954. fn into_value(self) -> AttributeValue {
  955. AttributeValue::Text(self)
  956. }
  957. }
  958. impl IntoAttributeValue for f32 {
  959. fn into_value(self) -> AttributeValue {
  960. AttributeValue::Float(self as _)
  961. }
  962. }
  963. impl IntoAttributeValue for f64 {
  964. fn into_value(self) -> AttributeValue {
  965. AttributeValue::Float(self)
  966. }
  967. }
  968. impl IntoAttributeValue for i8 {
  969. fn into_value(self) -> AttributeValue {
  970. AttributeValue::Int(self as _)
  971. }
  972. }
  973. impl IntoAttributeValue for i16 {
  974. fn into_value(self) -> AttributeValue {
  975. AttributeValue::Int(self as _)
  976. }
  977. }
  978. impl IntoAttributeValue for i32 {
  979. fn into_value(self) -> AttributeValue {
  980. AttributeValue::Int(self as _)
  981. }
  982. }
  983. impl IntoAttributeValue for i64 {
  984. fn into_value(self) -> AttributeValue {
  985. AttributeValue::Int(self)
  986. }
  987. }
  988. impl IntoAttributeValue for isize {
  989. fn into_value(self) -> AttributeValue {
  990. AttributeValue::Int(self as _)
  991. }
  992. }
  993. impl IntoAttributeValue for i128 {
  994. fn into_value(self) -> AttributeValue {
  995. AttributeValue::Int(self as _)
  996. }
  997. }
  998. impl IntoAttributeValue for u8 {
  999. fn into_value(self) -> AttributeValue {
  1000. AttributeValue::Int(self as _)
  1001. }
  1002. }
  1003. impl IntoAttributeValue for u16 {
  1004. fn into_value(self) -> AttributeValue {
  1005. AttributeValue::Int(self as _)
  1006. }
  1007. }
  1008. impl IntoAttributeValue for u32 {
  1009. fn into_value(self) -> AttributeValue {
  1010. AttributeValue::Int(self as _)
  1011. }
  1012. }
  1013. impl IntoAttributeValue for u64 {
  1014. fn into_value(self) -> AttributeValue {
  1015. AttributeValue::Int(self as _)
  1016. }
  1017. }
  1018. impl IntoAttributeValue for usize {
  1019. fn into_value(self) -> AttributeValue {
  1020. AttributeValue::Int(self as _)
  1021. }
  1022. }
  1023. impl IntoAttributeValue for u128 {
  1024. fn into_value(self) -> AttributeValue {
  1025. AttributeValue::Int(self as _)
  1026. }
  1027. }
  1028. impl IntoAttributeValue for bool {
  1029. fn into_value(self) -> AttributeValue {
  1030. AttributeValue::Bool(self)
  1031. }
  1032. }
  1033. impl IntoAttributeValue for Arguments<'_> {
  1034. fn into_value(self) -> AttributeValue {
  1035. AttributeValue::Text(self.to_string())
  1036. }
  1037. }
  1038. impl IntoAttributeValue for Rc<dyn AnyValue> {
  1039. fn into_value(self) -> AttributeValue {
  1040. AttributeValue::Any(self)
  1041. }
  1042. }
  1043. impl<T> IntoAttributeValue for ListenerCallback<T> {
  1044. fn into_value(self) -> AttributeValue {
  1045. AttributeValue::Listener(self.erase())
  1046. }
  1047. }
  1048. impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
  1049. fn into_value(self) -> AttributeValue {
  1050. match self {
  1051. Some(val) => val.into_value(),
  1052. None => AttributeValue::None,
  1053. }
  1054. }
  1055. }
  1056. pub struct AnyFmtMarker;
  1057. impl<T> IntoAttributeValue<AnyFmtMarker> for T
  1058. where
  1059. T: DioxusFormattable,
  1060. {
  1061. fn into_value(self) -> AttributeValue {
  1062. AttributeValue::Text(self.format().to_string())
  1063. }
  1064. }
  1065. /// A trait for anything that has a dynamic list of attributes
  1066. pub trait HasAttributes {
  1067. /// Push an attribute onto the list of attributes
  1068. fn push_attribute<T>(
  1069. self,
  1070. name: &'static str,
  1071. ns: Option<&'static str>,
  1072. attr: impl IntoAttributeValue<T>,
  1073. volatile: bool,
  1074. ) -> Self;
  1075. }