1use downcast_rs::{impl_downcast, Downcast};
2use std::any::TypeId;
3use std::fmt::Debug;
4
5use crate::common::sourcemap::SourcePos;
6use crate::common::TypeKey;
7use crate::parser::extset::NodeExtSet;
8use crate::parser::inline::Text;
9use crate::parser::renderer::HTMLRenderer;
10use crate::plugins::cmark::inline::newline::Softbreak;
11use crate::Renderer;
12
13/// Single node in the CommonMark AST.
14#[derive(Debug)]
15#[readonly::make]
16pub struct Node {
17 /// Array of child nodes.
18 pub children: Vec<Node>,
19
20 /// Source mapping info.
21 pub srcmap: Option<SourcePos>,
22
23 /// Custom data specific to this token.
24 pub ext: NodeExtSet,
25
26 /// Additional attributes to be added to resulting html.
27 pub attrs: Vec<(&'static str, String)>,
28
29 /// Type name, used for debugging.
30 #[readonly]
31 pub node_type: TypeKey,
32
33 /// Storage for arbitrary token-specific data.
34 #[readonly]
35 pub node_value: Box<dyn NodeValue>,
36}
37
38impl Node {
39 /// Create a new [Node](Node) with a custom value.
40 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 /// Return std::any::type_name() of node value.
52 pub fn name(&self) -> &'static str {
53 self.node_type.name
54 }
55
56 /// Check that this node value is of given type.
57 pub fn is<T: NodeValue>(&self) -> bool {
58 self.node_type.id == TypeId::of::<T>()
59 }
60
61 /// Downcast node value to specific type.
62 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 // performance note: `node_type.id` improves walk speed by a LOT by removing indirection
66 // (~5% of overall program speed), so having type id duplicated in Node is very beneficial;
67 // we can also remove extra check with downcast_unchecked, but it doesn't do much
68 //Some(unsafe { &*(&*self.node_value as *const dyn NodeValue as *const T) })
69 } else {
70 None
71 }
72 }
73
74 /// Downcast node value to specific type.
75 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 // performance note: see above
79 //Some(unsafe { &mut *(&mut *self.node_value as *mut dyn NodeValue as *mut T) })
80 } else {
81 None
82 }
83 }
84
85 /// Render this node to HTML.
86 pub fn render(&self) -> String {
87 let mut fmt = HTMLRenderer::<false>::new();
88 fmt.render(self);
89 fmt.into()
90 }
91
92 /// Render this node to XHTML, it adds slash to self-closing tags like this: `<img />`.
93 ///
94 /// This mode exists for compatibility with CommonMark tests.
95 pub fn xrender(&self) -> String {
96 let mut fmt = HTMLRenderer::<true>::new();
97 fmt.render(self);
98 fmt.into()
99 }
100
101 /// Replace custom value with another value (this is roughly equivalent
102 /// to replacing the entire node and copying children and sourcemaps).
103 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 /// Execute function `f` recursively on every member of AST tree
109 /// (using preorder deep-first search).
110 pub fn walk<'a>(&'a self, mut f: impl FnMut(&'a Node, u32)) {
111 // performance note: this is faster than emulating recursion using vec stack
112 fn walk_recursive<'b>(node: &'b Node, depth: u32, f: &mut impl FnMut(&'b 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 /// Execute function `f` recursively on every member of AST tree
125 /// (using preorder deep-first search).
126 pub fn walk_mut(&mut self, mut f: impl FnMut(&mut Node, u32)) {
127 // performance note: this is faster than emulating recursion using vec stack
128 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 /// Execute function `f` recursively on every member of AST tree
141 /// (using postorder deep-first search).
142 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 /// Execute function `f` recursively on every member of AST tree
156 /// (using postorder deep-first search).
157 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 /// Walk recursively through child nodes and collect all text nodes
171 /// into a single string.
172 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 /// Create empty Node. Empty node should only be used as placeholder for functions like
202 /// std::mem::take, and it cannot be rendered.
203 fn default() -> Self {
204 Node::new(NodeEmpty)
205 }
206}
207
208/// Contents of the specific AST node.
209pub trait NodeValue : Debug + Downcast {
210 /// Output HTML corresponding to this node using Renderer API.
211 ///
212 /// Example implementation looks like this:
213 /// ```rust
214 /// # const IGNORE : &str = stringify! {
215 /// fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
216 /// fmt.open("div", &[]);
217 /// fmt.contents(&node.children);
218 /// fmt.close("div");
219 /// fmt.cr();
220 /// }
221 /// # };
222 /// ```
223 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);