Skip to content

Commit d45ecc1

Browse files
committed
function to walk over all elements (recursive)
1 parent 2a8c7f3 commit d45ecc1

4 files changed

Lines changed: 105 additions & 2 deletions

File tree

src/dom/element.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use ownable::{IntoOwned, ToBorrowed, ToOwned};
77
use serde::Serialize;
88
use std::borrow::Cow;
99
use std::default::Default;
10+
use std::ops::ControlFlow;
1011

1112
/// Normal: `<div></div>` or Void: `<meta/>`and `<meta>`
1213
#[derive(Debug, Clone, Serialize, PartialEq)]
@@ -68,3 +69,66 @@ impl Default for Element<'static> {
6869
}
6970
}
7071
}
72+
73+
pub enum WalkResult {
74+
Continue,
75+
Skip,
76+
Break,
77+
}
78+
79+
impl<'a> Element<'a> {
80+
#[inline]
81+
pub fn for_each_element<F>(&mut self, mut f: F)
82+
where
83+
F: FnMut(&mut Element<'a>) -> WalkResult,
84+
{
85+
let _ = for_each_element(self.children.as_mut_slice(), &mut f);
86+
}
87+
88+
#[inline]
89+
pub async fn for_each_element_async<F>(&mut self, mut f: F)
90+
where
91+
F: AsyncFnMut(&mut Element<'a>) -> WalkResult,
92+
{
93+
let _ = for_each_element_async(self.children.as_mut_slice(), &mut f).await;
94+
}
95+
}
96+
97+
pub(crate) fn for_each_element<'a, F>(tree: &mut [Node<'a>], f: &mut F) -> ControlFlow<(), ()>
98+
where
99+
F: FnMut(&mut Element<'a>) -> WalkResult,
100+
{
101+
for n in tree {
102+
if let Node::Element(e) = n {
103+
match f(e) {
104+
WalkResult::Continue => {
105+
for_each_element(e.children.as_mut_slice(), f)?;
106+
}
107+
WalkResult::Skip => (),
108+
WalkResult::Break => return ControlFlow::Break(()),
109+
}
110+
}
111+
}
112+
ControlFlow::Continue(())
113+
}
114+
115+
pub(crate) async fn for_each_element_async<'a, F>(
116+
tree: &mut [Node<'a>],
117+
f: &mut F,
118+
) -> ControlFlow<(), ()>
119+
where
120+
F: AsyncFnMut(&mut Element<'a>) -> WalkResult,
121+
{
122+
for n in tree {
123+
if let Node::Element(e) = n {
124+
match f(e).await {
125+
WalkResult::Continue => {
126+
Box::pin(for_each_element_async(e.children.as_mut_slice(), f)).await?;
127+
}
128+
WalkResult::Skip => (),
129+
WalkResult::Break => return ControlFlow::Break(()),
130+
}
131+
}
132+
}
133+
ControlFlow::Continue(())
134+
}

src/dom/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod span;
1818
pub mod vecmap;
1919
pub mod vecset;
2020

21+
use crate::dom::element::{WalkResult, for_each_element, for_each_element_async};
2122
#[cfg(feature = "source-span")]
2223
use crate::dom::span::SourceSpan;
2324
use element::{Element, ElementVariant};
@@ -368,4 +369,20 @@ impl<'a> Dom<'a> {
368369
}
369370
Ok(attribute)
370371
}
372+
373+
#[inline]
374+
pub fn for_each_element<F>(&mut self, mut f: F)
375+
where
376+
F: FnMut(&mut Element) -> WalkResult,
377+
{
378+
let _ = for_each_element(self.children.as_mut_slice(), &mut f);
379+
}
380+
381+
#[inline]
382+
pub async fn for_each_element_async<F>(&mut self, mut f: F)
383+
where
384+
F: AsyncFnMut(&mut Element) -> WalkResult,
385+
{
386+
let _ = for_each_element_async(self.children.as_mut_slice(), &mut f).await;
387+
}
371388
}

src/dom/node.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use super::element::Element;
2-
use crate::Text;
1+
use super::element::{Element, for_each_element_async};
2+
use crate::dom::element::for_each_element;
3+
use crate::{Text, WalkResult};
34
use ownable::{IntoOwned, ToBorrowed, ToOwned};
45
use serde::Serialize;
56

@@ -46,6 +47,26 @@ impl<'a> Node<'a> {
4647
_ => None,
4748
}
4849
}
50+
51+
#[inline]
52+
pub fn for_each_element<F>(&mut self, mut f: F)
53+
where
54+
F: FnMut(&mut Element<'a>) -> WalkResult,
55+
{
56+
if let Node::Element(e) = self {
57+
let _ = for_each_element(e.children.as_mut_slice(), &mut f);
58+
}
59+
}
60+
61+
#[inline]
62+
pub async fn for_each_element_async<F>(&mut self, mut f: F)
63+
where
64+
F: AsyncFnMut(&mut Element<'a>) -> WalkResult,
65+
{
66+
if let Node::Element(e) = self {
67+
let _ = for_each_element_async(e.children.as_mut_slice(), &mut f).await;
68+
}
69+
}
4970
}
5071

5172
impl<'a> IntoIterator for &'a Node<'a> {

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ use grammar::Rule;
104104

105105
pub use crate::dom::Dom;
106106
pub use crate::dom::DomVariant;
107+
pub use crate::dom::element::WalkResult;
107108
pub use crate::dom::element::{Element, ElementVariant};
108109
pub use crate::dom::html::{Attribute, Text};
109110
pub use crate::dom::node::Node;

0 commit comments

Comments
 (0)