cmark_writer/traits/
formatting.rs

1//! Formatting and rendering traits
2//!
3//! This module provides a unified system for rendering content to different formats.
4//! It combines the high-level format abstraction with concrete rendering implementations.
5
6use crate::error::WriteResult;
7use crate::writer::{CommonMarkWriter, HtmlWriter};
8
9// ==== Core Rendering Traits ====
10
11/// CommonMark rendering trait - using concrete types for dyn compatibility
12pub trait CommonMarkRenderable: super::core::NodeContent {
13    /// Render to CommonMark format
14    fn render_commonmark(&self, writer: &mut CommonMarkWriter) -> WriteResult<()>;
15}
16
17/// HTML rendering trait - using concrete types for dyn compatibility
18pub trait HtmlRenderable: super::core::NodeContent {
19    /// Render to HTML format
20    fn render_html(&self, writer: &mut HtmlWriter) -> WriteResult<()>;
21}
22
23// ==== High-Level Format Traits ====
24
25/// Generic format trait - supports multiple output formats
26pub trait Format<W> {
27    /// Format self to the specified writer
28    fn format(&self, writer: &mut W) -> WriteResult<()>;
29}
30
31/// Convenience trait for CommonMark format
32pub trait ToCommonMark {
33    /// Format to CommonMark
34    fn to_commonmark(&self, writer: &mut CommonMarkWriter) -> WriteResult<()>;
35}
36
37/// Convenience trait for HTML format
38pub trait ToHtml {
39    /// Format to HTML
40    fn to_html(&self, writer: &mut HtmlWriter) -> WriteResult<()>;
41}
42
43// ==== Automatic Implementations ====
44
45/// Automatically implement ToCommonMark for types that implement `Format<CommonMarkWriter>`
46impl<T> ToCommonMark for T
47where
48    T: Format<CommonMarkWriter>,
49{
50    fn to_commonmark(&self, writer: &mut CommonMarkWriter) -> WriteResult<()> {
51        self.format(writer)
52    }
53}
54
55/// Automatically implement ToHtml for types that implement `Format<HtmlWriter>`
56impl<T> ToHtml for T
57where
58    T: Format<HtmlWriter>,
59{
60    fn to_html(&self, writer: &mut HtmlWriter) -> WriteResult<()> {
61        self.format(writer)
62    }
63}
64
65/// Bridge implementation: Format -> Renderable
66impl<T> CommonMarkRenderable for T
67where
68    T: ToCommonMark + super::core::NodeContent,
69{
70    fn render_commonmark(&self, writer: &mut CommonMarkWriter) -> WriteResult<()> {
71        self.to_commonmark(writer)
72    }
73}
74
75impl<T> HtmlRenderable for T
76where
77    T: ToHtml + super::core::NodeContent,
78{
79    fn render_html(&self, writer: &mut HtmlWriter) -> WriteResult<()> {
80        self.to_html(writer)
81    }
82}
83
84// ==== Multi-Format Support ====
85
86/// Multi-format node trait - unified interface for rendering to multiple formats
87///
88/// This trait provides a unified multi-format rendering interface for custom nodes.
89/// All custom nodes should support at least CommonMark format.
90pub trait MultiFormat: ToCommonMark {
91    /// Check if HTML format is supported
92    ///
93    /// Returns false by default. Only types supporting HTML need to override this.
94    fn supports_html(&self) -> bool {
95        false
96    }
97
98    /// HTML rendering implementation
99    ///
100    /// By default, generates a comment indicating HTML is not supported.
101    /// Types that support HTML should override this method.
102    fn html_format(&self, writer: &mut HtmlWriter) -> WriteResult<()> {
103        writer
104            .raw_html(&format!(
105                "<!-- HTML rendering not implemented for {} -->",
106                std::any::type_name::<Self>()
107            ))
108            .map_err(Into::into)
109    }
110
111    /// Render to the appropriate format based on writer type
112    fn render_multi<W>(&self, writer: &mut W) -> WriteResult<()>
113    where
114        W: std::any::Any + 'static,
115    {
116        if let Some(cm_writer) =
117            (writer as &mut dyn std::any::Any).downcast_mut::<CommonMarkWriter>()
118        {
119            self.to_commonmark(cm_writer)
120        } else if let Some(html_writer) =
121            (writer as &mut dyn std::any::Any).downcast_mut::<HtmlWriter>()
122        {
123            if self.supports_html() {
124                self.html_format(html_writer)
125            } else {
126                Err(crate::error::WriteError::custom(
127                    "HTML format not supported for this node type",
128                ))
129            }
130        } else {
131            Err(crate::error::WriteError::custom("Unsupported writer type"))
132        }
133    }
134}
135
136/// Automatically implement MultiFormat for types that implement both ToCommonMark and ToHtml
137impl<T> MultiFormat for T
138where
139    T: ToCommonMark + ToHtml,
140{
141    fn supports_html(&self) -> bool {
142        true
143    }
144
145    fn html_format(&self, writer: &mut HtmlWriter) -> WriteResult<()> {
146        self.to_html(writer)
147    }
148}