facet_xml_node/
parser.rs

1//! DomParser implementation for walking Element trees.
2
3use std::borrow::Cow;
4use std::fmt;
5
6use facet_dom::{DomDeserializer, DomEvent, DomParser, DomSerializer, WriteScalar};
7
8use crate::{Content, Element};
9
10#[derive(Debug)]
11pub struct ElementParseError;
12
13impl fmt::Display for ElementParseError {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        write!(f, "element parse error")
16    }
17}
18
19impl std::error::Error for ElementParseError {}
20
21/// Deserialize from an Element tree into a typed value.
22pub fn from_element<T>(
23    element: &Element,
24) -> Result<T, facet_dom::DomDeserializeError<ElementParseError>>
25where
26    T: facet_core::Facet<'static>,
27{
28    let parser = ElementParser::new(element);
29    let mut de = DomDeserializer::new_owned(parser);
30    de.deserialize()
31}
32
33/// Parser that walks an Element tree and emits DomEvents.
34pub struct ElementParser<'a> {
35    /// Stack of frames - each frame is an element being processed
36    stack: Vec<Frame<'a>>,
37    /// Peeked event
38    peeked: Option<DomEvent<'static>>,
39    /// Current depth for skip_node
40    depth: usize,
41}
42
43struct Frame<'a> {
44    element: &'a Element,
45    state: FrameState,
46    attr_iter: std::collections::hash_map::Iter<'a, String, String>,
47    child_idx: usize,
48}
49
50#[derive(Clone, Copy, PartialEq)]
51enum FrameState {
52    Start,
53    Attrs,
54    ChildrenStart,
55    Children,
56    ChildrenEnd,
57    NodeEnd,
58    Done,
59}
60
61impl<'a> ElementParser<'a> {
62    pub fn new(root: &'a Element) -> Self {
63        Self {
64            stack: vec![Frame {
65                element: root,
66                state: FrameState::Start,
67                attr_iter: root.attrs.iter(),
68                child_idx: 0,
69            }],
70            peeked: None,
71            depth: 0,
72        }
73    }
74
75    fn read_next(&mut self) -> Result<Option<DomEvent<'static>>, ElementParseError> {
76        loop {
77            let frame = match self.stack.last_mut() {
78                Some(f) => f,
79                None => return Ok(None),
80            };
81
82            match frame.state {
83                FrameState::Start => {
84                    self.depth += 1;
85                    frame.state = FrameState::Attrs;
86                    return Ok(Some(DomEvent::NodeStart {
87                        tag: Cow::Owned(frame.element.tag.clone()),
88                        namespace: None,
89                    }));
90                }
91                FrameState::Attrs => {
92                    if let Some((name, value)) = frame.attr_iter.next() {
93                        return Ok(Some(DomEvent::Attribute {
94                            name: Cow::Owned(name.clone()),
95                            value: Cow::Owned(value.clone()),
96                            namespace: None,
97                        }));
98                    }
99                    frame.state = FrameState::ChildrenStart;
100                }
101                FrameState::ChildrenStart => {
102                    frame.state = FrameState::Children;
103                    return Ok(Some(DomEvent::ChildrenStart));
104                }
105                FrameState::Children => {
106                    if frame.child_idx < frame.element.children.len() {
107                        let child = &frame.element.children[frame.child_idx];
108                        frame.child_idx += 1;
109
110                        match child {
111                            Content::Text(t) => {
112                                return Ok(Some(DomEvent::Text(Cow::Owned(t.clone()))));
113                            }
114                            Content::Element(e) => {
115                                // Push new frame for child element
116                                self.stack.push(Frame {
117                                    element: e,
118                                    state: FrameState::Start,
119                                    attr_iter: e.attrs.iter(),
120                                    child_idx: 0,
121                                });
122                                // Loop to process the new frame
123                            }
124                        }
125                    } else {
126                        frame.state = FrameState::ChildrenEnd;
127                    }
128                }
129                FrameState::ChildrenEnd => {
130                    frame.state = FrameState::NodeEnd;
131                    return Ok(Some(DomEvent::ChildrenEnd));
132                }
133                FrameState::NodeEnd => {
134                    frame.state = FrameState::Done;
135                    self.depth -= 1;
136                    return Ok(Some(DomEvent::NodeEnd));
137                }
138                FrameState::Done => {
139                    self.stack.pop();
140                }
141            }
142        }
143    }
144}
145
146impl<'a> DomParser<'static> for ElementParser<'a> {
147    type Error = ElementParseError;
148
149    fn next_event(&mut self) -> Result<Option<DomEvent<'static>>, Self::Error> {
150        if let Some(event) = self.peeked.take() {
151            return Ok(Some(event));
152        }
153        self.read_next()
154    }
155
156    fn peek_event(&mut self) -> Result<Option<&DomEvent<'static>>, Self::Error> {
157        if self.peeked.is_none() {
158            self.peeked = self.read_next()?;
159        }
160        Ok(self.peeked.as_ref())
161    }
162
163    fn skip_node(&mut self) -> Result<(), Self::Error> {
164        let start_depth = self.depth;
165        loop {
166            match self.next_event()? {
167                Some(DomEvent::NodeEnd) if self.depth < start_depth => break,
168                None => break,
169                _ => {}
170            }
171        }
172        Ok(())
173    }
174
175    fn format_namespace(&self) -> Option<&'static str> {
176        Some("xml")
177    }
178}
179
180#[derive(Debug)]
181pub struct ElementSerializeError;
182
183impl fmt::Display for ElementSerializeError {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        write!(f, "element serialize error")
186    }
187}
188
189impl std::error::Error for ElementSerializeError {}
190
191/// Serialize a typed value into an Element tree.
192pub fn to_element<T>(
193    value: &T,
194) -> Result<Element, facet_dom::DomSerializeError<ElementSerializeError>>
195where
196    T: facet_core::Facet<'static>,
197{
198    let mut serializer = ElementSerializer::default();
199    let peek = facet_reflect::Peek::new(value);
200    facet_dom::serialize(&mut serializer, peek)?;
201    serializer.finish()
202}
203
204/// Serializer that builds an Element tree from DomSerializer callbacks.
205#[derive(Default)]
206pub struct ElementSerializer {
207    /// Stack of elements being built
208    stack: Vec<Element>,
209    /// The root element (after serialization completes)
210    root: Option<Element>,
211    /// Whether the current field should be serialized as an attribute
212    is_attribute: bool,
213    /// Whether the current field should be serialized as text content
214    is_text: bool,
215    /// Whether the current field is an xml::elements list
216    is_elements: bool,
217    /// Whether the current field is a tag field
218    is_tag: bool,
219    /// Whether the current field is a doctype field
220    is_doctype: bool,
221}
222
223impl ElementSerializer {
224    /// Finish serialization and return the root element.
225    fn finish(mut self) -> Result<Element, facet_dom::DomSerializeError<ElementSerializeError>> {
226        // If we have a root, return it
227        if let Some(root) = self.root.take() {
228            return Ok(root);
229        }
230
231        // Otherwise, pop the last element from the stack
232        if self.stack.len() == 1 {
233            Ok(self.stack.pop().unwrap())
234        } else {
235            Err(facet_dom::DomSerializeError::Backend(ElementSerializeError))
236        }
237    }
238}
239
240impl DomSerializer for ElementSerializer {
241    type Error = ElementSerializeError;
242
243    fn element_start(&mut self, tag: &str, _namespace: Option<&str>) -> Result<(), Self::Error> {
244        self.stack.push(Element::new(tag));
245        Ok(())
246    }
247
248    fn attribute(
249        &mut self,
250        name: &str,
251        value: facet_reflect::Peek<'_, '_>,
252        _namespace: Option<&str>,
253    ) -> Result<(), Self::Error> {
254        // Convert the value to a string using format_scalar (before borrowing elem)
255        if let Some(value_str) = self.format_scalar(value) {
256            let elem = self.stack.last_mut().ok_or(ElementSerializeError)?;
257            elem.attrs.insert(name.to_string(), value_str);
258        }
259        Ok(())
260    }
261
262    fn children_start(&mut self) -> Result<(), Self::Error> {
263        Ok(())
264    }
265
266    fn children_end(&mut self) -> Result<(), Self::Error> {
267        Ok(())
268    }
269
270    fn element_end(&mut self, _tag: &str) -> Result<(), Self::Error> {
271        let elem = self.stack.pop().ok_or(ElementSerializeError)?;
272
273        if let Some(parent) = self.stack.last_mut() {
274            parent.children.push(Content::Element(elem));
275        } else {
276            self.root = Some(elem);
277        }
278        Ok(())
279    }
280
281    fn text(&mut self, content: &str) -> Result<(), Self::Error> {
282        if let Some(elem) = self.stack.last_mut() {
283            elem.children.push(Content::Text(content.to_string()));
284        } else {
285            return Err(ElementSerializeError);
286        }
287        Ok(())
288    }
289
290    fn format_namespace(&self) -> Option<&'static str> {
291        Some("xml")
292    }
293
294    fn field_metadata(&mut self, field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
295        let Some(field_def) = field.field else {
296            // For flattened map entries, treat them as attributes
297            self.is_attribute = true;
298            self.is_text = false;
299            self.is_elements = false;
300            self.is_tag = false;
301            self.is_doctype = false;
302            return Ok(());
303        };
304
305        // Check field attributes
306        self.is_attribute = field_def.get_attr(Some("xml"), "attribute").is_some();
307        self.is_text = field_def.get_attr(Some("xml"), "text").is_some();
308        self.is_elements = field_def.get_attr(Some("xml"), "elements").is_some();
309        self.is_tag = field_def.get_attr(Some("xml"), "tag").is_some();
310        self.is_doctype = field_def.get_attr(Some("xml"), "doctype").is_some();
311        Ok(())
312    }
313
314    fn is_attribute_field(&self) -> bool {
315        self.is_attribute
316    }
317
318    fn is_text_field(&self) -> bool {
319        self.is_text
320    }
321
322    fn is_elements_field(&self) -> bool {
323        self.is_elements
324    }
325
326    fn is_tag_field(&self) -> bool {
327        self.is_tag
328    }
329
330    fn is_doctype_field(&self) -> bool {
331        self.is_doctype
332    }
333
334    fn clear_field_state(&mut self) {
335        self.is_attribute = false;
336        self.is_text = false;
337        self.is_elements = false;
338        self.is_tag = false;
339        self.is_doctype = false;
340    }
341}