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}