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;