add ElementBodyBuilder

This commit is contained in:
Jacob Lifshay 2026-01-02 03:09:49 -08:00
parent 104ee37933
commit 3fc0e92f95
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
2 changed files with 65 additions and 7 deletions

View file

@ -1092,4 +1092,59 @@ impl TextLineFontKind {
}
}
#[derive(Debug)]
struct ElementBodyBuilder<'a> {
containing_element: &'a mut xml_tree::Element,
stack: Vec<xml_tree::Element>,
}
impl<'a> ElementBodyBuilder<'a> {
fn new(containing_element: &'a mut xml_tree::Element) -> Self {
Self {
containing_element,
stack: Vec::with_capacity(5),
}
}
fn shrink_stack(&mut self, new_len: usize) {
while new_len < self.stack.len() {
let Some(element) = self.stack.pop() else {
unreachable!();
};
self.insert_point().children.push(element);
}
}
fn set_tag_stack<'b>(&mut self, tag_stack: impl IntoIterator<Item = &'b str>) {
let mut new_len = 0;
for (i, tag) in tag_stack.into_iter().enumerate() {
new_len = i + 1;
if i >= self.stack.len() {
self.stack.push(xml_tree::Element::new(tag.into(), []));
} else if self.stack[i].tag.normal() != Some(tag) {
self.shrink_stack(new_len);
}
}
self.shrink_stack(new_len);
}
fn write_text(&mut self, text: impl Borrow<str>) {
let text = text.borrow();
let insert_point = self.insert_point();
if let Some(child) = insert_point.children.last_mut() {
child.tail += text;
} else {
insert_point.text += text;
}
}
fn insert_point(&mut self) -> &mut xml_tree::Element {
self.stack.last_mut().unwrap_or(self.containing_element)
}
fn scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
let retval = f(self);
self.flush();
retval
}
fn flush(&mut self) {
self.set_tag_stack([]);
}
}
fn main() {}

View file

@ -157,6 +157,15 @@ impl fmt::Display for Element {
}
impl Element {
pub(crate) fn new(tag: String, attrib: impl IntoIterator<Item = (String, String)>) -> Self {
Self {
tag: ElementTag::Normal(tag),
attrib: Vec::from_iter(attrib),
text: String::new(),
children: Vec::new(),
tail: String::new(),
}
}
/// equivalent to python `"".join(self.itertext())`
pub(crate) fn inner_text(&self) -> String {
let mut retval = String::new();
@ -186,13 +195,7 @@ impl Element {
tag: String,
attrib: impl IntoIterator<Item = (String, String)>,
) -> &mut Self {
self.children.push(Self {
tag: ElementTag::Normal(tag),
attrib: Vec::from_iter(attrib),
text: String::new(),
children: Vec::new(),
tail: String::new(),
});
self.children.push(Self::new(tag, attrib));
self.children.last_mut().expect("just pushed")
}
}