Skip to main content

devela/code/util/
const.rs

1// devela/src/code/util/const.rs
2//
3//! Defines the [CONST!] macro.
4//
5// IMPROVE: the examples showing the last two arms [hidden|inline] macro_export
6// IMPROVE: support constants with macro metavariables
7
8#[doc = crate::_tags!(code construction)]
9/// A helper for constructing macro constants.
10#[doc = crate::_doc_meta!{location("code/util")}]
11///
12/// It accepts either a series of expressions or a series of functions.
13///
14/// # Examples
15/// ```
16/// # use devela::CONST;
17///
18/// CONST!{ /* Supports empty declarations */ }
19///
20/// // Supports any expresion
21/// CONST!{EXPR = 2 * 15 / 3}
22/// assert_eq![EXPR![], 10u8];
23/// assert_eq![EXPR![], 10i8];
24///
25/// CONST!{
26///     /// Supports docs, attributes, and visibility.
27///     #[macro_export] // attribute needed if public
28///     pub ARRAY = [1, 2, 3]
29/// }
30/// assert_eq![ARRAY![], [1u16, 2, 3]];
31/// assert_eq![ARRAY![], [1i32, 2, 3]];
32///
33/// // Supports multiple definitions of constant expressions, ended with ;
34/// CONST! {
35///     DOC_1 = "Document expression." ;
36///     DOC_2 = "Document expression." ;
37/// }
38/// assert_eq![DOC_1![], "Document expression."];
39///
40/// // A good use-case is for repeated documentation
41/// /// Function 1, version a.
42/// #[doc = DOC_1!()]
43/// pub fn version_1a() {}
44/// /// Function 1, version b.
45/// #[doc = DOC_1!()]
46/// pub fn version_1b() {}
47///
48/// // Supports multiple definitions of constants functions, ended with ;
49/// CONST! {
50///     /// Supports *const* functions.
51///     FN_1 =
52///     /// Returns `n × 5`.
53///     #[inline] #[must_use]
54///     pub const fn fn_1(n: i32) -> i64 { (n * 5) as i64 };
55///
56///     /// You can repeat functions.
57///     pub(crate) FN_2 = pub const fn fn_2(c: char) { };
58///
59///     /// Supports optional *unsafe*.
60///     FN_3 = pub const unsafe fn fn_3() {};
61///
62///     // NOTE: It's not possible to mix expressions and functions in the same invocation.
63///     // EXPR_ERR = "Compile fails if this line is uncommented";
64/// }
65/// pub struct Fns;
66/// impl Fns {
67///     FN_1!{}
68///     FN_2!{}
69///     FN_3!{}
70/// }
71///
72/// assert_eq![Fns::fn_1(0i32), 0i64];
73/// assert_eq![Fns::fn_1(5), 25];
74/// let _: () = Fns::fn_2('a');
75/// unsafe { Fns::fn_3(); }
76///
77/// // Supports giving a shared visibility for all defined constants
78/// CONST! { pub(crate),
79///     E1 = 1 + 1;
80///     E2 = 2 + 2;
81///     // pub E3 = 3 + 3; // shared visibility can't be overriden
82/// }
83/// CONST! { pub(crate),
84///     F1 = pub const fn f1(a: i32) -> i32 { a + 1 };
85///     F2 = pub const fn f2(a: i32) -> i32 { a + 2 };
86///     // pub F3 = pub const fn f3(a: i32) -> i32 { a + 3 };
87/// }
88/// ```
89// Related links
90// - https://doc.rust-lang.org/reference/items/external-blocks.html#functions
91#[macro_export]
92#[cfg_attr(cargo_primary_package, doc(hidden))]
93macro_rules! CONST· {
94    (
95    // Either multiple `const fn`
96    $(
97        $(#[$CONST_ATTRS:meta])*
98        $item_vis:vis $CONST_NAME:ident =
99            $(#[$fn_attrs:meta])*
100            $fn_vis:vis const
101            $(async$($_a:block)?)? $(safe$($_s:block)?)? $(unsafe$($_u:block)?)?
102            fn $fn:ident($($param:ident: $param_ty:ty),* $(,)?)
103        $(-> $fn_return:ty)?
104        $fn_body:block
105    );* $(;)?) => {
106        $(
107            $(#[$CONST_ATTRS])*
108            #[allow(unused_macros)]
109            macro_rules! $CONST_NAME {
110                () => {
111                    $(#[$fn_attrs])*
112                    $fn_vis const $(async$($_a)?)? $(safe$($_s)?)? $(unsafe$($_u)?)?
113                    fn $fn($($param: $param_ty),*) $(-> $fn_return)? $fn_body
114                }
115            }
116            #[allow(unused_imports)]
117            $item_vis use $CONST_NAME;
118        )*
119    };
120    (
121    $shared_vis:vis, // (shared visibility alternative)
122    $(
123        $(#[$CONST_ATTRS:meta])*
124        $CONST_NAME:ident =
125            $(#[$fn_attrs:meta])*
126            $fn_vis:vis const
127            $(async$($_a:block)?)? $(safe$($_s:block)?)? $(unsafe$($_u:block)?)?
128            fn $fn:ident($($param:ident: $param_ty:ty),* $(,)?)
129        $(-> $fn_return:ty)?
130        $fn_body:block
131    );* $(;)?) => {
132        $(
133            $(#[$CONST_ATTRS])*
134            #[allow(unused_macros)]
135            macro_rules! $CONST_NAME {
136                () => {
137                    $(#[$fn_attrs])*
138                    $shared_vis const $(async$($_a)?)? $(safe$($_s)?)? $(unsafe$($_u)?)?
139                    fn $fn($($param: $param_ty),*) $(-> $fn_return)? $fn_body
140                }
141            }
142            #[allow(unused_imports)]
143            $shared_vis use $CONST_NAME;
144        )*
145    };
146    (
147
148    // Either multiple expressions
149    $(
150        $(#[$CONST_ATTRS:meta])*
151        $item_vis:vis $CONST_NAME:ident = $expr:expr
152     );* $(;)?) => {
153        $(
154            $(#[$CONST_ATTRS])*
155            #[allow(unused_macro)]
156            macro_rules! $CONST_NAME { () => { $expr } }
157            #[allow(unused_imports)]
158            $item_vis use $CONST_NAME;
159        )*
160    };
161    (
162    $shared_vis:vis, // (shared visibility alternative)
163    $(
164        $(#[$CONST_ATTRS:meta])*
165        $CONST_NAME:ident = $expr:expr
166     );* $(;)?) => {
167        $(
168            $(#[$CONST_ATTRS])*
169            #[allow(unused_macro)]
170            macro_rules! $CONST_NAME { () => { $expr } }
171            #[allow(unused_imports)]
172            $shared_vis use $CONST_NAME;
173        )*
174    };
175    (
176
177    // Either multiple hidden macros exported
178    hidden macro_export,
179    $(
180        $(#[$CONST_ATTRS:meta])*
181        $CONST_NAME:ident = $expr:expr
182     );* $(;)?) => { $crate::paste! {
183        $(
184            $(#[$CONST_ATTRS])*
185            #[allow(unused_macro)]
186            #[macro_export]
187            #[doc(hidden)]
188            macro_rules! [<$CONST_NAME _·>] { () => { $expr } }
189
190            #[doc(hidden)]
191            #[allow(unused_imports)]
192            pub use [<$CONST_NAME _·>] as $CONST_NAME;
193        )*
194    }};
195    (
196
197    // Either multiple visible macros exported
198    inline macro_export,
199    $(
200        $(#[$CONST_ATTRS:meta])*
201        $CONST_NAME:ident = $expr:expr
202     );* $(;)?) => { $crate::paste! {
203        $(
204            $(#[$CONST_ATTRS])*
205            #[allow(unused_macro)]
206            #[macro_export]
207            #[cfg_attr(cargo_primary_package, doc(hidden))]
208            macro_rules! [<$CONST_NAME _·>] { () => { $expr } }
209
210            #[doc(inline)]
211            #[allow(unused_imports)]
212            pub use [<$CONST_NAME _·>] as $CONST_NAME;
213        )*
214    }};
215}
216#[doc(inline)]
217pub use CONST· as CONST;