From 74045f24f8bd2dcee6c1dcde0f9db63de192d7e5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <jorge@japaric.io> Date: Sat, 23 Dec 2017 11:24:18 +0100 Subject: [PATCH] safe `&'static mut` references through a runtime checked macro --- src/macros.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/macros.rs b/src/macros.rs index 465d759..bd43b4f 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) + } + }) + } +} -- GitLab