devela/code/util/
const.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// devela::code::util::const

/// A helper for constructing macro constants.
///
/// It accepts either a series of expressions or a series of functions.
///
/// # Examples
/// ```
/// # use devela::CONST;
/// CONST!{ /* Supports empty declarations */ }
///
/// // Supports any expresion
/// CONST!{EXPR = 2 * 15 / 3}
/// assert_eq![EXPR![], 10u8];
/// assert_eq![EXPR![], 10i8];
///
/// CONST!{
///     /// Supports docs, attributes, and visibility.
///     #[macro_export] // attribute needed if public
///     pub ARRAY = [1, 2, 3]
/// }
/// assert_eq![ARRAY![], [1u16, 2, 3]];
/// assert_eq![ARRAY![], [1i32, 2, 3]];
///
/// // Supports multiple definitions of constant expressions, ended with ;
/// CONST! {
///     DOC_1 = "Document expression." ;
///     DOC_2 = "Document expression." ;
/// }
/// assert_eq![DOC_1![], "Document expression."];
///
/// // A good use-case is for repeated documentation
/// /// Function 1, version a.
/// #[doc = DOC_1!()]
/// pub fn version_1a() {}
/// /// Function 1, version b.
/// #[doc = DOC_1!()]
/// pub fn version_1b() {}
///
/// // Supports multiple definitions of constants functions, ended with ;
/// CONST! {
///     /// Supports *const* functions.
///     FN_1 =
///     /// Returns `n × 5`.
///     #[inline] #[must_use]
///     pub const fn fn_1(n: i32) -> i64 { (n * 5) as i64 };
///
///     /// You can repeat functions.
///     pub(crate) FN_2 = pub const fn fn_2(c: char) { };
///
///     /// Supports optional *unsafe*.
///     FN_3 = pub const unsafe fn fn_3() {};
///
///     // NOTE: It's not possible to mix expressions and functions in the same invocation.
///     // EXPR_ERR = "Compile fails if this line is uncommented";
/// }
/// pub struct Fns;
/// impl Fns {
///     FN_1!{}
///     FN_2!{}
///     FN_3!{}
/// }
///
/// assert_eq![Fns::fn_1(0i32), 0i64];
/// assert_eq![Fns::fn_1(5), 25];
/// let _: () = Fns::fn_2('a');
/// unsafe { Fns::fn_3(); }
///
/// // Supports giving a shared visibility for all defined constants
/// CONST! { pub(crate),
///     E1 = 1 + 1;
///     E2 = 2 + 2;
///     // pub E3 = 3 + 3; // shared visibility can't be overriden
/// }
/// CONST! { pub(crate),
///     F1 = pub const fn f1(a: i32) -> i32 { a + 1 };
///     F2 = pub const fn f2(a: i32) -> i32 { a + 2 };
///     // pub F3 = pub const fn f3(a: i32) -> i32 { a + 3 };
/// }
/// ```
// Related links
// - https://doc.rust-lang.org/reference/items/external-blocks.html#functions
#[doc(hidden)]
#[macro_export]
macro_rules! _CONST {
    (
    // Either multiple `const fn`
    $(
        $(#[$CONST_ATTRS:meta])*
        $item_vis:vis $CONST_NAME:ident =
            $(#[$fn_attrs:meta])*
            $fn_vis:vis const
            $(async$($_a:block)?)? $(safe$($_s:block)?)? $(unsafe$($_u:block)?)?
            fn $fn:ident($($param:ident: $param_ty:ty),* $(,)?)
        $(-> $fn_return:ty)?
        $fn_body:block
    );* $(;)?) => {
        $(
            $(#[$CONST_ATTRS])*
            #[allow(unused_macros)]
            macro_rules! $CONST_NAME {
                () => {
                    $(#[$fn_attrs])*
                    $fn_vis const $(async$($_a)?)? $(safe$($_s)?)? $(unsafe$($_u)?)?
                    fn $fn($($param: $param_ty),*) $(-> $fn_return)? $fn_body
                }
            }
            $item_vis use $CONST_NAME;
        )*
    };
    (
    $shared_vis:vis, // (shared visibility alternative)
    $(
        $(#[$CONST_ATTRS:meta])*
        $CONST_NAME:ident =
            $(#[$fn_attrs:meta])*
            $fn_vis:vis const
            $(async$($_a:block)?)? $(safe$($_s:block)?)? $(unsafe$($_u:block)?)?
            fn $fn:ident($($param:ident: $param_ty:ty),* $(,)?)
        $(-> $fn_return:ty)?
        $fn_body:block
    );* $(;)?) => {
        $(
            $(#[$CONST_ATTRS])*
            #[allow(unused_macros)]
            macro_rules! $CONST_NAME {
                () => {
                    $(#[$fn_attrs])*
                    $shared_vis const $(async$($_a)?)? $(safe$($_s)?)? $(unsafe$($_u)?)?
                    fn $fn($($param: $param_ty),*) $(-> $fn_return)? $fn_body
                }
            }
            $shared_vis use $CONST_NAME;
        )*
    };
    (

    // Either multiple expressions
    $(
        $(#[$CONST_ATTRS:meta])*
        $item_vis:vis $CONST_NAME:ident = $expr:expr
     );* $(;)?) => {
        $(
            $(#[$CONST_ATTRS])*
            #[allow(unused_macro)]
            macro_rules! $CONST_NAME { () => { $expr } }
            $item_vis use $CONST_NAME;
        )*
    };
    (
    $shared_vis:vis, // (shared visibility alternative)
    $(
        $(#[$CONST_ATTRS:meta])*
        $CONST_NAME:ident = $expr:expr
     );* $(;)?) => {
        $(
            $(#[$CONST_ATTRS])*
            #[allow(unused_macro)]
            macro_rules! $CONST_NAME { () => { $expr } }
            $shared_vis use $CONST_NAME;
        )*
    };
}
#[doc(inline)]
pub use _CONST as CONST;