ziyy_core/resolver/document/
mod.rs

1use std::{
2    cell::RefCell,
3    fmt::{self, Debug, Display, Formatter},
4    rc::Rc,
5};
6
7use crate::{
8    common::Span,
9    parser::{
10        chunk::{Chunk, ChunkData},
11        tag_parser::tag::{Tag, TagType},
12    },
13};
14pub use node::Node;
15
16mod display;
17mod iter;
18mod node;
19
20#[derive(Clone)]
21
22pub struct Document<'a> {
23    recycled: RefCell<Vec<u32>>,
24    nodes: RefCell<Vec<Rc<Node<'a>>>>,
25}
26
27impl<'a> Document<'a> {
28    /// Creates a new Document
29    pub fn new() -> Rc<Document<'a>> {
30        let doc = Rc::new(Self {
31            recycled: RefCell::new(Vec::with_capacity(64)),
32            nodes: RefCell::new(vec![]),
33        });
34
35        let mut tag = Tag::default();
36        tag.set_name("$root".to_string());
37        tag.r#type = TagType::Open;
38
39        let node = Rc::new(Node::new(
40            0,
41            Chunk {
42                data: ChunkData::Tag(tag),
43                span: Span::inserted(),
44            },
45            Rc::downgrade(&Rc::clone(&doc)),
46        ));
47
48        {
49            let mut nodes = doc.nodes.borrow_mut();
50            nodes.push(node)
51        }
52
53        doc
54    }
55
56    pub fn get(&self, id: u32) -> Rc<Node<'a>> {
57        self.nodes.borrow()[id as usize].clone()
58    }
59
60    pub fn node(&self, id: u32) -> Rc<Node<'a>> {
61        self.get(id)
62    }
63
64    pub fn root(&self) -> Rc<Node<'a>> {
65        self.get(0)
66    }
67
68    pub fn orphan(self: &Rc<Document<'a>>, chunk: Chunk<'a>) -> Rc<Node<'a>> {
69        let doc = Rc::downgrade(&Rc::clone(self));
70        let mut nodes = self.nodes.borrow_mut();
71        let id = nodes.len();
72
73        let node: Rc<Node>;
74
75        let mut recycled = self.recycled.borrow_mut();
76        if let Some(id) = recycled.pop() {
77            node = Rc::new(Node::new(id, chunk, doc));
78            nodes[id as usize] = node.clone();
79        } else {
80            node = Rc::new(Node::new(
81                id.try_into().expect("maximum nodes exceeded"),
82                chunk,
83                doc,
84            ));
85            nodes.push(node.clone());
86        }
87        node
88    }
89
90    #[allow(clippy::len_without_is_empty)]
91    pub fn len(&self) -> usize {
92        self.nodes.borrow().len()
93    }
94}
95
96impl<'a> Debug for Document<'a> {
97    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
98        use iter::Edge;
99        if f.alternate() {
100            write!(f, "Document {{")?;
101            for edge in self.root().traverse() {
102                match edge {
103                    Edge::Open(node) if node.has_children() => {
104                        write!(f, " {:#?} => {{", node.chunk())?;
105                    }
106                    Edge::Open(node) if node.next_sibling().is_some() => {
107                        write!(f, " {:#?},", node.chunk())?;
108                    }
109                    Edge::Open(node) => {
110                        write!(f, " {:#?}", node.chunk())?;
111                    }
112                    Edge::Close(node) if node.has_children() => {
113                        if node.next_sibling().is_some() {
114                            write!(f, " }},")?;
115                        } else {
116                            write!(f, " }}")?;
117                        }
118                    }
119                    _ => {}
120                }
121            }
122            write!(f, " }}")
123        } else {
124            f.debug_struct("Document")
125                .field("nodes", &self.nodes)
126                .finish()
127        }
128    }
129}
130
131impl<'a> Display for Document<'a> {
132    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
133        use display::Indentation;
134        use iter::Edge;
135
136        let mut indent: Indentation = Indentation::new(true);
137
138        for edge in self.root().traverse() {
139            match edge {
140                Edge::Open(node) if node.has_children() => {
141                    indent.indent(node.next_sibling().is_some());
142                    writeln!(f, "{indent}{:#}", node.chunk().borrow())?;
143                }
144                Edge::Open(node) => {
145                    indent.indent(node.next_sibling().is_some());
146                    writeln!(f, "{indent}{:#}", node.chunk().borrow())?;
147                    indent.deindent();
148                }
149                Edge::Close(node) if node.has_children() => {
150                    indent.deindent();
151                }
152                _ => {}
153            }
154        }
155        Ok(())
156    }
157}