Skip to main content

oak_pretty_print/
to_doc.rs

1use crate::Document;
2use alloc::{boxed::Box, string::String, vec::Vec};
3
4/// A trait for types that can be converted to a document for pretty printing.
5///
6/// This trait is used to define how types should be formatted as documents.
7/// It supports formatting parameters through the associated `Params` type,
8/// which defaults to `()` if not specified.
9///
10/// # Example
11/// ```rust
12/// use oak_pretty_print::{AsDocument, Doc};
13///
14/// // Define a type with custom formatting parameters
15/// struct MyType {
16///     value: i32,
17/// }
18///
19/// // Define formatting parameters for MyType
20/// #[derive(Default)]
21/// struct MyTypeParams {
22///     indent: usize,
23/// }
24///
25/// // Implement AsDocument for MyType with custom parameters
26/// impl AsDocument for MyType {
27///     type Params = MyTypeParams;
28///
29///     fn as_document(&self, params: &Self::Params) -> Doc<'_> {
30///         // Use params to customize formatting
31///         Doc::text(format!("MyType({}) with indent {}", self.value, params.indent))
32///     }
33/// }
34///
35/// // Create an instance of MyType
36/// let my_type = MyType { value: 42 };
37///
38/// // Format it with custom parameters
39/// let params = MyTypeParams { indent: 2 };
40/// let doc = my_type.as_document(&params);
41/// ```
42pub trait AsDocument {
43    /// The type of parameters used for formatting.
44    /// Defaults to `()` if not specified.
45    type Params = ();
46
47    /// Converts this type to a document for pretty printing.
48    ///
49    /// # Parameters
50    /// - `params`: Formatting parameters specific to this type.
51    ///
52    /// # Returns
53    /// A `Document` representing the formatted type.
54    fn as_document(&self, params: &Self::Params) -> Document<'_>;
55}
56
57/// A trait for types that can be converted to a document value, potentially consuming the input.
58pub trait ToDocument<'a> {
59    /// Converts this type to a document value.
60    fn to_document(self) -> Document<'a>;
61}
62
63impl AsDocument for String {
64    fn as_document(&self, _params: &Self::Params) -> Document<'_> {
65        Document::Text(self.as_str().into())
66    }
67}
68
69impl AsDocument for str {
70    fn as_document(&self, _params: &Self::Params) -> Document<'_> {
71        Document::Text(self.into())
72    }
73}
74
75impl<'a> AsDocument for Document<'a> {
76    fn as_document(&self, _params: &Self::Params) -> Document<'_> {
77        self.clone()
78    }
79}
80
81impl<T: AsDocument> AsDocument for Vec<T> {
82    type Params = T::Params;
83
84    fn as_document(&self, params: &Self::Params) -> Document<'_> {
85        Document::Concat(self.iter().map(|t| t.as_document(params)).collect())
86    }
87}
88
89impl<T: AsDocument> AsDocument for Option<T> {
90    type Params = T::Params;
91
92    fn as_document(&self, params: &Self::Params) -> Document<'_> {
93        match self {
94            Some(t) => t.as_document(params),
95            None => Document::Nil,
96        }
97    }
98}
99
100impl<T: AsDocument + ?Sized> AsDocument for &T {
101    type Params = T::Params;
102
103    fn as_document(&self, params: &Self::Params) -> Document<'_> {
104        (**self).as_document(params)
105    }
106}
107
108impl<T: AsDocument + ?Sized> AsDocument for Box<T> {
109    type Params = T::Params;
110
111    fn as_document(&self, params: &Self::Params) -> Document<'_> {
112        self.as_ref().as_document(params)
113    }
114}
115
116impl<'a> ToDocument<'a> for Document<'a> {
117    fn to_document(self) -> Document<'a> {
118        self
119    }
120}
121
122impl<'a, T: AsDocument + ?Sized> ToDocument<'a> for &'a T
123where
124    T::Params: Default,
125{
126    fn to_document(self) -> Document<'a> {
127        self.as_document(&T::Params::default())
128    }
129}
130
131impl<'a> ToDocument<'a> for String {
132    fn to_document(self) -> Document<'a> {
133        Document::Text(self.into())
134    }
135}