diff --git a/src/macros.rs b/src/macros.rs index 465d759e4b027922c042c4f1b9ed5d6167d884b7..bd43b4f100b897c0297f76b9210cb67c82e5766b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -22,3 +22,44 @@ macro_rules! iprintln { iprint!($channel, concat!($fmt, "\n"), $($arg)*); }; } + +/// Macro to create an statically allocated value +/// +/// This macro returns a value with type `Option<&'static mut $ty>`. `Some($expr)` will be returned +/// the first time the macro is executed; further calls will return `None`. To avoid `unwrap`ping a +/// `None` variant the caller must ensure that the macro is called from a function that's executed +/// at most once in the whole lifetime of the program. +/// +/// # Example +/// +/// ``` ignore +/// fn main() { +/// // OK if `main` is executed only once +/// let x: &'static mut bool = static_!(: bool = false).unwrap(); +/// +/// let y = alias(); +/// // BAD this second call to `alias` will definitively `panic!` +/// let y_alias = alias(); +/// } +/// +/// fn alias() -> &'static mut bool { +/// static_!(: bool = false).unwrap() +/// } +/// ``` +#[macro_export] +macro_rules! static_ { + (: $ty:ty = $expr:expr) => { + $crate::interrupt::free(|_| unsafe { + static mut USED: bool = false; + static mut VAR: $ty = $expr; + + if USED { + None + } else { + USED = true; + let var: &'static mut _ = &mut VAR; + Some(var) + } + }) + } +}