markdown_that/parser/
node.rs1use downcast_rs::{Downcast, impl_downcast};
2use std::any::TypeId;
3use std::fmt::Debug;
4
5use crate::Renderer;
6use crate::common::TypeKey;
7use crate::common::sourcemap::SourcePos;
8use crate::parser::extset::NodeExtSet;
9use crate::parser::inline::Text;
10use crate::parser::renderer::HTMLRenderer;
11use crate::plugins::cmark::inline::newline::Softbreak;
12
13#[derive(Debug)]
15#[readonly::make]
16pub struct Node {
17 pub children: Vec<Node>,
19
20 pub srcmap: Option<SourcePos>,
22
23 pub ext: NodeExtSet,
25
26 pub attrs: Vec<(&'static str, String)>,
28
29 #[readonly]
31 pub node_type: TypeKey,
32
33 #[readonly]
35 pub node_value: Box<dyn NodeValue>,
36}
37
38impl Node {
39 pub fn new<T: NodeValue>(value: T) -> Self {
41 Self {
42 children: Vec::new(),
43 srcmap: None,
44 attrs: Vec::new(),
45 ext: NodeExtSet::new(),
46 node_type: TypeKey::of::<T>(),
47 node_value: Box::new(value),
48 }
49 }
50
51 pub fn name(&self) -> &'static str {
53 self.node_type.name
54 }
55
56 pub fn is<T: NodeValue>(&self) -> bool {
58 self.node_type.id == TypeId::of::<T>()
59 }
60
61 pub fn cast<T: NodeValue>(&self) -> Option<&T> {
63 if self.node_type.id == TypeId::of::<T>() {
64 Some(self.node_value.downcast_ref::<T>().unwrap())
65 } else {
70 None
71 }
72 }
73
74 pub fn cast_mut<T: NodeValue>(&mut self) -> Option<&mut T> {
76 if self.node_type.id == TypeId::of::<T>() {
77 Some(self.node_value.downcast_mut::<T>().unwrap())
78 } else {
81 None
82 }
83 }
84
85 pub fn render(&self) -> String {
87 let mut fmt = HTMLRenderer::<false>::new();
88 fmt.render(self);
89 fmt.into()
90 }
91
92 pub fn xrender(&self) -> String {
96 let mut fmt = HTMLRenderer::<true>::new();
97 fmt.render(self);
98 fmt.into()
99 }
100
101 pub fn replace<T: NodeValue>(&mut self, value: T) {
104 self.node_type = TypeKey::of::<T>();
105 self.node_value = Box::new(value);
106 }
107
108 pub fn walk(&self, mut f: impl FnMut(&Node, u32)) {
111 fn walk_recursive(node: &Node, depth: u32, f: &mut impl FnMut(&Node, u32)) {
113 f(node, depth);
114 for n in node.children.iter() {
115 stacker::maybe_grow(64 * 1024, 1024 * 1024, || {
116 walk_recursive(n, depth + 1, f);
117 });
118 }
119 }
120
121 walk_recursive(self, 0, &mut f);
122 }
123
124 pub fn walk_mut(&mut self, mut f: impl FnMut(&mut Node, u32)) {
127 fn walk_recursive(node: &mut Node, depth: u32, f: &mut impl FnMut(&mut Node, u32)) {
129 f(node, depth);
130 for n in node.children.iter_mut() {
131 stacker::maybe_grow(64 * 1024, 1024 * 1024, || {
132 walk_recursive(n, depth + 1, f);
133 });
134 }
135 }
136
137 walk_recursive(self, 0, &mut f);
138 }
139
140 pub fn walk_post(&self, mut f: impl FnMut(&Node, u32)) {
143 fn walk_recursive(node: &Node, depth: u32, f: &mut impl FnMut(&Node, u32)) {
144 for n in node.children.iter() {
145 stacker::maybe_grow(64 * 1024, 1024 * 1024, || {
146 walk_recursive(n, depth + 1, f);
147 });
148 }
149 f(node, depth);
150 }
151
152 walk_recursive(self, 0, &mut f);
153 }
154
155 pub fn walk_post_mut(&mut self, mut f: impl FnMut(&mut Node, u32)) {
158 fn walk_recursive(node: &mut Node, depth: u32, f: &mut impl FnMut(&mut Node, u32)) {
159 for n in node.children.iter_mut() {
160 stacker::maybe_grow(64 * 1024, 1024 * 1024, || {
161 walk_recursive(n, depth + 1, f);
162 });
163 }
164 f(node, depth);
165 }
166
167 walk_recursive(self, 0, &mut f);
168 }
169
170 pub fn collect_text(&self) -> String {
173 let mut result = String::new();
174
175 self.walk(|node, _| {
176 if let Some(text) = node.cast::<Text>() {
177 result.push_str(text.content.as_str());
178 } else if node.is::<Softbreak>() {
179 result.push('\n');
180 }
181 });
182
183 result
184 }
185}
186
187impl Drop for Node {
188 fn drop(&mut self) {
189 self.walk_post_mut(|node, _| {
190 drop(std::mem::take(&mut node.children));
191 });
192 }
193}
194
195#[derive(Debug)]
196#[doc(hidden)]
197pub struct NodeEmpty;
198impl NodeValue for NodeEmpty {}
199
200impl Default for Node {
201 fn default() -> Self {
204 Node::new(NodeEmpty)
205 }
206}
207
208pub trait NodeValue: Debug + Downcast {
210 fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
224 let _ = fmt;
225 unimplemented!("{} doesn't implement render", node.name());
226 }
227}
228
229impl_downcast!(NodeValue);