Skip to content

Commit

Permalink
add singleton macro
Browse files Browse the repository at this point in the history
  • Loading branch information
gnxlxnxx committed Nov 12, 2021
1 parent be2927e commit 71394fb
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ extern crate bit_field;
pub mod asm;
pub mod interrupt;
pub mod register;

#[macro_use]
mod macros;
54 changes: 54 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/// Macro to create a mutable reference to a 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.
///
/// # Note
/// this macro is unsound on multi-core systems
///
/// # Example
///
/// ``` no_run
/// use riscv::singleton;
///
/// fn main() {
/// // OK if `main` is executed only once
/// let x: &'static mut bool = singleton!(: bool = false).unwrap();
///
/// let y = alias();
/// // BAD this second call to `alias` will definitively `panic!`
/// let y_alias = alias();
/// }
///
/// fn alias() -> &'static mut bool {
/// singleton!(: bool = false).unwrap()
/// }
/// ```
#[macro_export]
macro_rules! singleton {
(: $ty:ty = $expr:expr) => {
$crate::interrupt::free(|_| {
static mut VAR: Option<$ty> = None;

#[allow(unsafe_code)]
let used = unsafe { VAR.is_some() };
if used {
None
} else {
let expr = $expr;

#[allow(unsafe_code)]
unsafe {
VAR = Some(expr)
}

#[allow(unsafe_code)]
unsafe {
VAR.as_mut()
}
}
})
};
}

0 comments on commit 71394fb

Please sign in to comment.