Skip to content

Commit 71394fb

Browse files
committed
add singleton macro
1 parent be2927e commit 71394fb

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ extern crate bit_field;
2222
pub mod asm;
2323
pub mod interrupt;
2424
pub mod register;
25+
26+
#[macro_use]
27+
mod macros;

src/macros.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/// Macro to create a mutable reference to a statically allocated value
2+
///
3+
/// This macro returns a value with type `Option<&'static mut $ty>`. `Some($expr)` will be returned
4+
/// the first time the macro is executed; further calls will return `None`. To avoid `unwrap`ping a
5+
/// `None` variant the caller must ensure that the macro is called from a function that's executed
6+
/// at most once in the whole lifetime of the program.
7+
///
8+
/// # Note
9+
/// this macro is unsound on multi-core systems
10+
///
11+
/// # Example
12+
///
13+
/// ``` no_run
14+
/// use riscv::singleton;
15+
///
16+
/// fn main() {
17+
/// // OK if `main` is executed only once
18+
/// let x: &'static mut bool = singleton!(: bool = false).unwrap();
19+
///
20+
/// let y = alias();
21+
/// // BAD this second call to `alias` will definitively `panic!`
22+
/// let y_alias = alias();
23+
/// }
24+
///
25+
/// fn alias() -> &'static mut bool {
26+
/// singleton!(: bool = false).unwrap()
27+
/// }
28+
/// ```
29+
#[macro_export]
30+
macro_rules! singleton {
31+
(: $ty:ty = $expr:expr) => {
32+
$crate::interrupt::free(|_| {
33+
static mut VAR: Option<$ty> = None;
34+
35+
#[allow(unsafe_code)]
36+
let used = unsafe { VAR.is_some() };
37+
if used {
38+
None
39+
} else {
40+
let expr = $expr;
41+
42+
#[allow(unsafe_code)]
43+
unsafe {
44+
VAR = Some(expr)
45+
}
46+
47+
#[allow(unsafe_code)]
48+
unsafe {
49+
VAR.as_mut()
50+
}
51+
}
52+
})
53+
};
54+
}

0 commit comments

Comments
 (0)