lazynodes.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //! Support for storing lazy-nodes on the stack
  2. //!
  3. //! This module provides support for a type called `LazyNodes` which is a micro-heap located on the stack to make calls
  4. //! to `rsx!` more efficient.
  5. //!
  6. //! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`ScopeState`] closures.
  7. //!
  8. //! This can be done either through boxing directly, or by using dynamic-sized-types and a custom allocator. In our case,
  9. //! we build a tiny alloactor in the stack and allocate the closure into that.
  10. //!
  11. //! The logic for this was borrowed from <https://docs.rs/stack_dst/0.6.1/stack_dst/>. Unfortunately, this crate does not
  12. //! support non-static closures, so we've implemented the core logic of `ValueA` in this module.
  13. #[allow(unused_imports)]
  14. use smallbox::{smallbox, space::S16, SmallBox};
  15. use crate::{innerlude::VNode, ScopeState};
  16. /// A concrete type provider for closures that build [`VNode`] structures.
  17. ///
  18. /// This struct wraps lazy structs that build [`VNode`] trees. Normally, we cannot perform a blanket implementation over
  19. /// closures, but if we wrap the closure in a concrete type, we can use it for different branches in matching.
  20. ///
  21. ///
  22. /// ```rust, ignore
  23. /// LazyNodes::new(|f| {
  24. /// static TEMPLATE: dioxus::core::Template = dioxus::core::Template {
  25. /// name: "main.rs:5:5:20", // Source location of the template for hot reloading
  26. /// roots: &[
  27. /// dioxus::core::TemplateNode::Element {
  28. /// tag: dioxus_elements::div::TAG_NAME,
  29. /// namespace: dioxus_elements::div::NAME_SPACE,
  30. /// attrs: &[],
  31. /// children: &[],
  32. /// },
  33. /// ],
  34. /// node_paths: &[],
  35. /// attr_paths: &[],
  36. /// };
  37. /// dioxus::core::VNode {
  38. /// parent: None,
  39. /// key: None,
  40. /// template: std::cell::Cell::new(TEMPLATE),
  41. /// root_ids: dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(
  42. /// 1usize,
  43. /// f.bump(),
  44. /// )
  45. /// .into(),
  46. /// dynamic_nodes: f.bump().alloc([]),
  47. /// dynamic_attrs: f.bump().alloc([]),
  48. /// })
  49. /// }
  50. /// ```
  51. ///
  52. /// Find more information about how to construct [`VNode`] at <https://dioxuslabs.com/learn/0.4/contributing/walkthrough_readme#the-rsx-macro>
  53. pub struct LazyNodes<'a, 'b> {
  54. #[cfg(not(miri))]
  55. inner: SmallBox<dyn FnMut(&'a ScopeState) -> VNode<'a> + 'b, S16>,
  56. #[cfg(miri)]
  57. inner: Box<dyn FnMut(&'a ScopeState) -> VNode<'a> + 'b>,
  58. }
  59. impl<'a, 'b> LazyNodes<'a, 'b> {
  60. /// Create a new [`LazyNodes`] closure, optimistically placing it onto the stack.
  61. ///
  62. /// If the closure cannot fit into the stack allocation (16 bytes), then it
  63. /// is placed on the heap. Most closures will fit into the stack, and is
  64. /// the most optimal way to use the creation function.
  65. pub fn new(val: impl FnOnce(&'a ScopeState) -> VNode<'a> + 'b) -> Self {
  66. // there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
  67. let mut slot = Some(val);
  68. Self {
  69. #[cfg(not(miri))]
  70. inner: smallbox!(move |f| {
  71. let val = slot.take().expect("cannot call LazyNodes twice");
  72. val(f)
  73. }),
  74. #[cfg(miri)]
  75. inner: Box::new(move |f| {
  76. let val = slot.take().expect("cannot call LazyNodes twice");
  77. val(f)
  78. }),
  79. }
  80. }
  81. /// Call the closure with the given factory to produce real [`VNode`].
  82. ///
  83. /// ```rust, ignore
  84. /// let f = LazyNodes::new(/* Closure for creating VNodes */);
  85. ///
  86. /// let node = f.call(cac);
  87. /// ```
  88. #[must_use]
  89. pub fn call(mut self, f: &'a ScopeState) -> VNode<'a> {
  90. (self.inner)(f)
  91. }
  92. }