state.rs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. use std::{cmp::Ordering, fmt::Debug};
  2. use anymap::AnyMap;
  3. use dioxus_core::ElementId;
  4. use fxhash::FxHashSet;
  5. use crate::node_ref::{NodeMask, NodeView};
  6. use crate::traversable::Traversable;
  7. /// Join two sorted iterators
  8. pub(crate) fn union_ordered_iter<T: Ord + Debug>(
  9. s_iter: impl Iterator<Item = T>,
  10. o_iter: impl Iterator<Item = T>,
  11. new_len_guess: usize,
  12. ) -> Vec<T> {
  13. let mut s_peekable = s_iter.peekable();
  14. let mut o_peekable = o_iter.peekable();
  15. let mut v = Vec::with_capacity(new_len_guess);
  16. while let Some(s_i) = s_peekable.peek() {
  17. while let Some(o_i) = o_peekable.peek() {
  18. match o_i.cmp(s_i) {
  19. Ordering::Greater => {
  20. break;
  21. }
  22. Ordering::Less => {
  23. v.push(o_peekable.next().unwrap());
  24. }
  25. Ordering::Equal => {
  26. o_peekable.next();
  27. break;
  28. }
  29. }
  30. }
  31. v.push(s_peekable.next().unwrap());
  32. }
  33. for o_i in o_peekable {
  34. v.push(o_i);
  35. }
  36. for w in v.windows(2) {
  37. debug_assert!(w[1] > w[0]);
  38. }
  39. v
  40. }
  41. /// This state is derived from children. For example a node's size could be derived from the size of children.
  42. /// Called when the current node's node properties are modified, a child's [ChildDepState] is modified or a child is removed.
  43. /// Called at most once per update.
  44. /// ```rust
  45. /// #[derive(Clone, Copy, PartialEq, Default)]
  46. /// struct Layout {
  47. /// width: u32,
  48. /// height: u32,
  49. /// }
  50. ///
  51. /// impl ChildDepState for Layout {
  52. /// type Ctx = ();
  53. /// // The layout depends on the layout of the children.
  54. /// type DepState = Layout;
  55. /// fn reduce<'a>(
  56. /// &mut self,
  57. /// _node: NodeView,
  58. /// children: impl Iterator<Item = &'a Self::DepState>,
  59. /// _ctx: &Self::Ctx,
  60. /// ) -> bool
  61. /// where
  62. /// Self::DepState: 'a{
  63. /// /// Children are layed out form left to right. The width of the parent is the sum of the widths and the max of the heights.
  64. /// let new = children.copied().reduce(|c1, c2| Layout{
  65. /// width: c1.width + c2.width,
  66. /// height: c1.height.max(c2.height)
  67. /// }).unwrap_or_default();
  68. /// let changed = new != self.combined;
  69. /// self = new;
  70. /// changed
  71. /// }
  72. /// }
  73. /// ```
  74. pub trait ChildDepState {
  75. /// The context is passed to the [ChildDepState::reduce] when it is resolved.
  76. type Ctx;
  77. /// A state from each child node that this node depends on. Typically this is Self, but it could be any state that is within the state tree.
  78. /// This must be either a [ChildDepState], or [NodeDepState].
  79. type DepState;
  80. /// The part of a node that this state cares about. This is used to determine if the state should be updated when a node is updated.
  81. const NODE_MASK: NodeMask = NodeMask::NONE;
  82. /// Resolve the state current node's state from the state of the children, the state of the node, and some external context.
  83. fn reduce<'a>(
  84. &mut self,
  85. node: NodeView,
  86. children: impl Iterator<Item = &'a Self::DepState>,
  87. ctx: &Self::Ctx,
  88. ) -> bool
  89. where
  90. Self::DepState: 'a;
  91. }
  92. /// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children.
  93. /// Called when the current node's node properties are modified or a parrent's [ParentDepState] is modified.
  94. /// Called at most once per update.
  95. /// ```rust
  96. /// use dioxus_native_core::node_ref::{NodeMask, AttributeMask, NodeView};
  97. /// use dioxus_native_core::state::*;
  98. ///
  99. /// #[derive(Clone, Copy, PartialEq)]
  100. /// struct FontSize(usize);
  101. ///
  102. /// impl ParentDepState for FontSize {
  103. /// type Ctx = ();
  104. /// // The font size depends on the font size of the parent element.
  105. /// type DepState = Self;
  106. /// const NODE_MASK: NodeMask =
  107. /// NodeMask::new_with_attrs(AttributeMask::Static(&[
  108. /// "font-size"
  109. /// ]));
  110. /// fn reduce<'a>(
  111. /// &mut self,
  112. /// node: NodeView,
  113. /// parent: Option<&'a Self::DepState>,
  114. /// ctx: &Self::Ctx,
  115. /// ) -> bool{
  116. /// let old = *self;
  117. /// // If the font size was set on the parent, it is passed down to the current element
  118. /// if let Some(parent) = parent{
  119. /// *self = parent;
  120. /// }
  121. /// // If the current node overrides the font size, use that size insead.
  122. /// for attr in node.attributes() {
  123. /// match attr.name {
  124. /// "font-size" => {
  125. /// self.0 = attr.value.as_text().unwrap().parse().unwrap();
  126. /// }
  127. /// // font-size is the only attribute we specified in the mask, so it is the only one we can see
  128. /// _ => unreachable!(),
  129. /// }
  130. /// }
  131. /// old != *self
  132. /// }
  133. /// }
  134. /// ```
  135. pub trait ParentDepState {
  136. /// The context is passed to the [ParentDepState::reduce] when it is resolved.
  137. type Ctx;
  138. /// A state from from the parent node that this node depends on. Typically this is Self, but it could be any state that is within the state tree.
  139. /// This must be either a [ParentDepState] or [NodeDepState]
  140. type DepState;
  141. /// The part of a node that this state cares about. This is used to determine if the state should be updated when a node is updated.
  142. const NODE_MASK: NodeMask = NodeMask::NONE;
  143. /// Resolve the state current node's state from the state of the parent node, the state of the node, and some external context.
  144. fn reduce<'a>(
  145. &mut self,
  146. node: NodeView,
  147. parent: Option<&'a Self::DepState>,
  148. ctx: &Self::Ctx,
  149. ) -> bool;
  150. }
  151. /// This state that is upadated lazily. For example any propertys that do not effect other parts of the dom like bg-color.
  152. /// Called when the current node's node properties are modified or a one of its dependanices are modified.
  153. /// Called at most once per update.
  154. /// NodeDepState is the only state that can accept multiple dependancies, but only from the current node.
  155. /// ```rust
  156. /// use dioxus_native_core::node_ref::{NodeMask, AttributeMask, NodeView};
  157. /// use dioxus_native_core::state::*;
  158. ///
  159. /// #[derive(Clone, Copy, PartialEq)]
  160. /// struct TabIndex(usize);
  161. ///
  162. /// impl NodeDepState for TabIndex {
  163. /// type Ctx = ();
  164. /// const NODE_MASK: NodeMask =
  165. /// NodeMask::new_with_attrs(AttributeMask::Static(&[
  166. /// "tabindex"
  167. /// ]));
  168. /// fn reduce(
  169. /// &mut self,
  170. /// node: NodeView,
  171. /// siblings: (),
  172. /// ctx: &(),
  173. /// ) -> bool {
  174. /// let old = self;
  175. /// for attr in node.attributes() {
  176. /// match attr.name {
  177. /// "tabindex" => {
  178. /// self.0 = attr.value.as_text().unwrap().parse().unwrap();
  179. /// }
  180. /// // tabindex is the only attribute we specified in the mask, so it is the only one we can see
  181. /// _ => unreachable!(),
  182. /// }
  183. /// }
  184. /// old != *self
  185. /// }
  186. /// }
  187. /// ```
  188. /// The generic argument (Depstate) must be a tuple containing any number of borrowed elements that are either a [ChildDepState], [ParentDepState] or [NodeDepState].
  189. // Todo: once GATs land we can model multable dependencies better
  190. pub trait NodeDepState<DepState = ()> {
  191. /// The state passed to [NodeDepState::reduce] when it is resolved.
  192. type Ctx;
  193. /// The part of a node that this state cares about. This is used to determine if the state should be updated when a node is updated.
  194. const NODE_MASK: NodeMask = NodeMask::NONE;
  195. /// Resolve the state current node's state from the state of the sibling states, the state of the node, and some external context.
  196. fn reduce(&mut self, node: NodeView, siblings: DepState, ctx: &Self::Ctx) -> bool;
  197. }
  198. /// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom].
  199. pub trait State: Default + Clone {
  200. #[doc(hidden)]
  201. fn update<'a, T: Traversable<Node = Self, Id = ElementId>>(
  202. dirty: &[(ElementId, NodeMask)],
  203. state_tree: &'a mut T,
  204. vdom: &'a dioxus_core::VirtualDom,
  205. ctx: &AnyMap,
  206. ) -> FxHashSet<ElementId>;
  207. }
  208. impl ChildDepState for () {
  209. type Ctx = ();
  210. type DepState = ();
  211. fn reduce<'a>(
  212. &mut self,
  213. _: NodeView,
  214. _: impl Iterator<Item = &'a Self::DepState>,
  215. _: &Self::Ctx,
  216. ) -> bool
  217. where
  218. Self::DepState: 'a,
  219. {
  220. false
  221. }
  222. }
  223. impl ParentDepState for () {
  224. type Ctx = ();
  225. type DepState = ();
  226. fn reduce<'a>(&mut self, _: NodeView, _: Option<&'a Self::DepState>, _: &Self::Ctx) -> bool {
  227. false
  228. }
  229. }
  230. impl NodeDepState<()> for () {
  231. type Ctx = ();
  232. fn reduce(&mut self, _: NodeView, _sibling: (), _: &Self::Ctx) -> bool {
  233. false
  234. }
  235. }