Skip to main content

code_docs/
documented_consts.rs

1#[derive(Clone, Copy)]
2pub struct DocumentedConstants {
3    names: &'static [&'static str],
4    types: &'static [&'static str],
5    values: &'static [&'static str],
6    docs: &'static [&'static [&'static str]],
7}
8
9impl DocumentedConstants {
10    /// Returns all constants names
11    pub fn constant_names(&self) -> &[&'static str] {
12        self.names
13    }
14
15    /// Returns all constants types
16    pub fn constant_types(&self) -> &[&'static str] {
17        self.types
18    }
19
20    /// Returns all constants values (raw string)
21    pub fn constant_values(&self) -> &[&'static str] {
22        self.values
23    }
24
25    pub fn constant_docs_raw(&self) -> &[&[&'static str]] {
26        self.docs
27    }
28
29    /// Returns all constants docstrings, one line being one string
30    pub fn constant_docs(&self) -> Vec<Vec<&'static str>> {
31        self.constant_docs_raw()
32            .iter().map(|x| {
33            x.into_iter()
34                .filter_map(|x| super::filter_docs(*x))
35                .collect::<Vec<_>>()
36        })
37        .collect::<Vec<_>>()
38    }
39
40    /// Returns string where each constant is shown with its type and docstring
41    pub fn commented_constants(&self) -> String {
42        use std::fmt::Write;
43
44        // NOTE write! is infallable on String
45
46        let mut output = String::new();
47        // just in case so the errors are not so cryptic below
48        assert_eq!(self.names.len(), self.types.len(), "Constant names and types length are not equal");
49        assert_eq!(self.names.len(), self.values.len(), "Constant names and values length are not equal");
50        assert_eq!(self.names.len(), self.docs.len(), "Constant names and docs length are not equal");
51
52        // NOTE im not showing value as it is usually ugly not understandable without processing
53        for (i, field) in self.names.iter().enumerate() {
54            // remove the extra newline
55            if i != 0 {
56                write!(output, "\n").unwrap();
57            }
58
59            // imitate rust comments
60            for comment in self.docs.get(i).unwrap().iter() {
61                if let Some(comment) = super::filter_docs(comment) {
62                    write!(output, "///{}\n", comment).unwrap();
63                }
64            }
65
66            write!(output, "{}: {}\n", field, self.types.get(i).unwrap()).unwrap();
67        }
68
69        output
70    }
71}
72
73/// Saves information about constants defined within in a constant
74#[macro_export]
75macro_rules! code_docs_constants {
76    (
77        $t_vis:vis $t_name:ident;
78
79        $(
80            $(#[$meta:meta])*
81            $vis:vis const $name:ident : $t:ty = $expr:expr ;
82        )*
83    ) => {
84        $t_vis const $t_name: $crate::DocumentedConstants = $crate::DocumentedConstants {
85            names: &[
86                $(
87                    stringify!($name),
88                )*
89            ],
90            types: &[
91                $(
92                    stringify!($t),
93                )*
94            ],
95            values: &[
96                $(
97                    stringify!($expr),
98                )*
99            ],
100            docs: &[
101                $(
102                    &[
103                        $(stringify!($meta),)*
104                    ],
105                )*
106            ],
107        };
108
109        $(
110            $(#[$meta])*
111            $vis const $name : $t = $expr ;
112        )*
113    }
114}
115
116#[cfg(test)]
117#[allow(unused)]
118mod tests {
119    code_docs_constants! {
120        pub DOCS;
121
122        const ENV_FEATURE1: &str = "something";
123
124        /// Does the thing with feature2
125        ///
126        /// Yes very important
127        #[allow(unused)]
128        const ENV_FEATURE2: usize = 666;
129    }
130
131    #[test]
132    fn test_constants() {
133        assert_eq!(DOCS.constant_names(), &["ENV_FEATURE1", "ENV_FEATURE2"]);
134        assert_eq!(DOCS.constant_types(), &["&str", "usize"]);
135        assert_eq!(DOCS.constant_values(), &["\"something\"", "666"]);
136
137        assert_eq!(DOCS.constant_docs_raw(), vec![
138            vec![],
139            vec![
140                "doc = r\" Does the thing with feature2\"",
141                "doc = r\"\"",
142                "doc = r\" Yes very important\"",
143                "allow(unused)"
144            ],
145        ]);
146
147        assert_eq!(DOCS.constant_docs(), vec![
148            vec![],
149            vec![
150            " Does the thing with feature2",
151            "",
152            " Yes very important",
153        ]]);
154    }
155}
156