ziyy_core/resolver/document/
mod.rs1use 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 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}