code_docs/
documented_enum.rs1#[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 fn variant_names() -> Vec<&'static str>;
8
9 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 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 fn commented_variants() -> String {
29 use std::fmt::Write;
30
31 let mut output = String::new();
34 let names = Self::variant_names();
35 let docs = Self::variant_docs();
36
37 assert_eq!(names.len(), docs.len(), "Variant names and field docs are not equal");
39
40 for (i, variant) in names.iter().enumerate() {
41 if i != 0 {
43 write!(output, "\n").unwrap();
44 }
45
46 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 #[derive(PartialEq, Eq, Debug)]
121 pub enum TestEnum {
122 VariantA,
127
128 VariantB,
130
131 #[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}