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;