Skip to main content

code_docs/
documented_enum.rs

1#[allow(dead_code)]
2pub trait DocumentedEnum {
3    fn enum_docs_raw() -> Vec<&'static str>;
4    fn variant_docs_raw() -> Vec<Vec<&'static str>>;
5
6    /// Returns all variants of the enum
7    fn variant_names() -> Vec<&'static str>;
8
9    /// Returns all docstrings of the enum itself
10    fn enum_docs() -> Vec<&'static str> {
11        Self::enum_docs_raw()
12            .into_iter()
13            .filter_map(super::filter_docs)
14            .collect::<Vec<_>>()
15    }
16
17    /// Returns all docstrings of each variant, each line is a separate string
18    fn variant_docs() -> Vec<Vec<&'static str>> {
19        Self::variant_docs_raw().into_iter().map(|x| {
20            x.into_iter()
21                .filter_map(super::filter_docs)
22                .collect::<Vec<_>>()
23        })
24        .collect::<Vec<_>>()
25    }
26
27    /// Returns a string shownig all variants and their docstrings
28    fn commented_variants() -> String {
29        use std::fmt::Write;
30
31        // NOTE write! is infallable on String
32
33        let mut output = String::new();
34        let names = Self::variant_names();
35        let docs = Self::variant_docs();
36
37        // just in case so the errors are not so cryptic below
38        assert_eq!(names.len(), docs.len(), "Variant names and field docs are not equal");
39
40        for (i, variant) in names.iter().enumerate() {
41            // remove the extra newline
42            if i != 0 {
43                write!(output, "\n").unwrap();
44            }
45
46            // imitate rust comments
47            for comment in docs.get(i).unwrap() {
48                write!(output, "///{}\n", comment).unwrap();
49            }
50
51            write!(output, "{}\n", variant).unwrap();
52        }
53
54        output
55    }
56}
57
58#[macro_export]
59macro_rules! code_docs_enum {
60    (
61        $(#[$meta:meta])*
62        $vis:vis enum $name:ident {
63            $(
64                $(#[$f_meta:meta])*
65                $f_ident:ident $(($($t:ty),*))?
66            ),* $(,)?
67        }
68    ) => {
69        $(#[$meta])*
70        $vis enum $name {
71            $(
72                $(#[$f_meta])*
73                $f_ident $(($($t),*))?,
74            )*
75        }
76
77        impl $crate::DocumentedEnum for $name {
78            fn enum_docs_raw() -> Vec<&'static str> {
79                vec![
80                    $(
81                        stringify!($meta),
82                    )*
83                ]
84            }
85
86            fn variant_names() -> Vec<&'static str> {
87                vec![
88                    $(
89                        stringify!($f_ident),
90                    )*
91                ]
92            }
93
94            fn variant_docs_raw() -> Vec<Vec<&'static str>> {
95                vec![
96                    $(
97                        vec![
98                            $(
99                                stringify!($f_meta),
100                            )*
101                        ],
102                    )*
103                ]
104            }
105        }
106    }
107}
108
109#[cfg(test)]
110#[allow(unused)]
111mod tests {
112    use super::*;
113
114    code_docs_enum! {
115
116        /// This is a test enum, there are many like it
117        /// but this one is mine
118        ///
119        /// This is something else important
120        #[derive(PartialEq, Eq, Debug)]
121        pub enum TestEnum {
122            // remember this is A!
123            /// Variant A not variant C or B
124            ///
125            /// Very important as well
126            VariantA,
127
128            /// This variant B and its not as important
129            VariantB,
130
131            /// And the least important is variant C
132            ///
133            /// There isn't much to say about it to be honest
134            #[allow(unused)]
135            VariantC,
136        }
137    }
138
139    #[test]
140    fn test_enum_docs() {
141        assert_eq!(TestEnum::enum_docs_raw(), vec![
142            "doc = r\" This is a test enum, there are many like it\"",
143            "doc = r\" but this one is mine\"",
144            "doc = r\"\"",
145            "doc = r\" This is something else important\"",
146            "derive(PartialEq, Eq, Debug)"
147        ]);
148
149        assert_eq!(TestEnum::enum_docs(), vec![
150            " This is a test enum, there are many like it",
151            " but this one is mine",
152            "",
153            " This is something else important"
154        ]);
155    }
156
157    #[test]
158    fn test_enum_variant_names() {
159        assert_eq!(TestEnum::variant_names(), vec![
160            "VariantA", "VariantB", "VariantC"
161        ]);
162    }
163
164    #[test]
165    fn test_enum_variant_docs() {
166        assert_eq!(TestEnum::variant_docs_raw(), vec![
167            vec![
168                "doc = r\" Variant A not variant C or B\"",
169                "doc = r\"\"", "doc = r\" Very important as well\""
170            ],
171            vec!["doc = r\" This variant B and its not as important\""],
172            vec![
173                "doc = r\" And the least important is variant C\"",
174                "doc = r\"\"",
175                "doc = r\" There isn't much to say about it to be honest\"",
176                "allow(unused)"
177            ]
178        ]);
179
180        assert_eq!(TestEnum::variant_docs(), vec![
181            vec![
182                " Variant A not variant C or B",
183                "", " Very important as well"
184            ],
185            vec![" This variant B and its not as important"],
186            vec![
187                " And the least important is variant C",
188                "",
189                " There isn't much to say about it to be honest",
190            ]
191        ]);
192    }
193
194    #[test]
195    fn test_enum_commented() {
196        assert_eq!(TestEnum::commented_variants(), "/// Variant A not variant C or B
197///
198/// Very important as well
199VariantA
200
201/// This variant B and its not as important
202VariantB
203
204/// And the least important is variant C
205///
206/// There isn't much to say about it to be honest
207VariantC
208".to_string());
209    }
210}