util.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. use crate::innerlude::{VNode, VirtualDom};
  2. /// An iterator that only yields "real" [`Element`]s. IE only Elements that are
  3. /// not [`VNode::Component`] or [`VNode::Fragment`], .
  4. pub struct ElementIdIterator<'a> {
  5. vdom: &'a VirtualDom,
  6. // Heuristically we should never bleed into 5 completely nested fragments/components
  7. // Smallvec lets us stack allocate our little stack machine so the vast majority of cases are sane
  8. stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 5]>,
  9. }
  10. impl<'a> ElementIdIterator<'a> {
  11. /// Create a new iterator from the given [`VirtualDom`] and [`VNode`]
  12. ///
  13. /// This will allow you to iterate through all the real childrne of the [`VNode`].
  14. pub fn new(vdom: &'a VirtualDom, node: &'a VNode<'a>) -> Self {
  15. Self {
  16. vdom,
  17. stack: smallvec::smallvec![(0, node)],
  18. }
  19. }
  20. }
  21. impl<'a> Iterator for ElementIdIterator<'a> {
  22. type Item = &'a VNode<'a>;
  23. fn next(&mut self) -> Option<&'a VNode<'a>> {
  24. let mut should_pop = false;
  25. let mut returned_node = None;
  26. let mut should_push = None;
  27. while returned_node.is_none() {
  28. if let Some((count, node)) = self.stack.last_mut() {
  29. match node {
  30. // We can only exit our looping when we get "real" nodes
  31. VNode::Element(_) | VNode::Text(_) | VNode::Placeholder(_) => {
  32. // We've recursed INTO an element/text
  33. // We need to recurse *out* of it and move forward to the next
  34. should_pop = true;
  35. returned_node = Some(&**node);
  36. }
  37. // If we get a fragment we push the next child
  38. VNode::Fragment(frag) => {
  39. let count = *count as usize;
  40. if count >= frag.children.len() {
  41. should_pop = true;
  42. } else {
  43. should_push = Some(&frag.children[count]);
  44. }
  45. }
  46. // For components, we load their root and push them onto the stack
  47. VNode::Component(sc) => {
  48. let scope = self.vdom.get_scope(sc.scope.get().unwrap()).unwrap();
  49. // Simply swap the current node on the stack with the root of the component
  50. *node = scope.root_node();
  51. }
  52. VNode::Template(_) => todo!(),
  53. }
  54. } else {
  55. // If there's no more items on the stack, we're done!
  56. return None;
  57. }
  58. if should_pop {
  59. self.stack.pop();
  60. if let Some((id, _)) = self.stack.last_mut() {
  61. *id += 1;
  62. }
  63. should_pop = false;
  64. }
  65. if let Some(push) = should_push {
  66. self.stack.push((0, push));
  67. should_push = None;
  68. }
  69. }
  70. returned_node
  71. }
  72. }