markdown_that/parser/
node.rs

1use 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/// 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 the 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 a 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 a 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 a 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 a 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 an AST tree
109    /// (using preorder deep-first search).
110    pub fn walk(&self, mut f: impl FnMut(&Node, u32)) {
111        // performance note: this is faster than emulating recursion using vec stack
112        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    /// Execute function `f` recursively on every member of an 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 an 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 an 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 a 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);