cmark_writer/macros/
custom_node.rs

1//! Custom node macro definitions
2//!
3//! This module provides a macro to simplify the implementation of custom CommonMark nodes.
4
5/// Automatically implement the CustomNode trait for custom node types
6///
7/// This macro automatically implements all necessary CustomNode trait methods. Developers only need to implement
8/// the `write_custom` and `is_block_custom` methods.
9///
10/// # Requirements
11///
12/// Types using this macro must implement the following traits:
13/// - `Debug`
14/// - `Clone`
15/// - `PartialEq`
16///
17/// And must implement the following methods:
18/// - `fn write_custom(&self, writer: &mut dyn CustomNodeWriter) -> cmark_writer::error::WriteResult<()>`
19/// - `fn is_block_custom(&self) -> bool`
20///
21/// # Example
22///
23/// ```rust
24/// use cmark_writer::ast::{CustomNodeWriter};
25/// use cmark_writer::error::WriteResult;
26/// use cmark_writer::derive_custom_node;
27///
28/// #[derive(Debug, Clone, PartialEq)]
29/// struct HighlightNode {
30///     content: String,
31///     color: String,
32/// }
33///
34/// // Use the macro to automatically implement the CustomNode trait
35/// derive_custom_node!(HighlightNode);
36///
37/// // Implement the necessary methods
38/// impl HighlightNode {
39///     // Implement the custom node's writing logic
40///     fn write_custom(&self, writer: &mut dyn CustomNodeWriter) -> WriteResult<()> {
41///         writer.write_str("<span style=\"background-color: ")?;
42///         writer.write_str(&self.color)?;
43///         writer.write_str("\">")?;
44///         writer.write_str(&self.content)?;
45///         writer.write_str("</span>")?;
46///         Ok(())
47///     }
48///     
49///     // Specify whether the node is a block-level node or an inline node
50///     fn is_block_custom(&self) -> bool {
51///         false // This is an inline element
52///     }
53/// }
54/// ```
55///
56/// # Generated code
57///
58/// For the above example, the macro will generate the following code:
59///
60/// ```rust,ignore
61/// impl CustomNode for HighlightNode {
62///     fn write(&self, writer: &mut dyn CustomNodeWriter) -> WriteResult<()> {
63///         self.write_custom(writer)
64///     }
65///
66///     fn clone_box(&self) -> Box<dyn CustomNode> {
67///         Box::new(self.clone())
68///     }
69///
70///     fn eq_box(&self, other: &dyn CustomNode) -> bool {
71///         if let Some(other) = other.as_any().downcast_ref::<Self>() {
72///             self == other
73///         } else {
74///             false
75///         }
76///     }
77///
78///     fn is_block(&self) -> bool {
79///         self.is_block_custom()
80///     }
81///
82///     fn as_any(&self) -> &dyn Any {
83///         self
84///     }
85/// }
86/// ```
87#[macro_export]
88macro_rules! derive_custom_node {
89    ($type:ty) => {
90        impl $crate::ast::CustomNode for $type {
91            fn write(
92                &self,
93                writer: &mut dyn $crate::ast::CustomNodeWriter,
94            ) -> $crate::error::WriteResult<()> {
95                self.write_custom(writer)
96            }
97
98            fn clone_box(&self) -> Box<dyn $crate::ast::CustomNode> {
99                Box::new(self.clone())
100            }
101
102            fn eq_box(&self, other: &dyn $crate::ast::CustomNode) -> bool {
103                if let Some(other) = other.as_any().downcast_ref::<Self>() {
104                    self == other
105                } else {
106                    false
107                }
108            }
109
110            fn is_block(&self) -> bool {
111                self.is_block_custom()
112            }
113
114            fn as_any(&self) -> &dyn std::any::Any {
115                self
116            }
117        }
118    };
119}