cortex_m/macros.rs
1/// Macro for sending a formatted string through an ITM channel
2#[macro_export]
3macro_rules! iprint {
4 ($channel:expr, $s:expr) => {
5 $crate::itm::write_str($channel, $s);
6 };
7 ($channel:expr, $($arg:tt)*) => {
8 $crate::itm::write_fmt($channel, format_args!($($arg)*));
9 };
10}
11
12/// Macro for sending a formatted string through an ITM channel, with a newline.
13#[macro_export]
14macro_rules! iprintln {
15 ($channel:expr) => {
16 $crate::itm::write_str($channel, "\n");
17 };
18 ($channel:expr, $fmt:expr) => {
19 $crate::itm::write_str($channel, concat!($fmt, "\n"));
20 };
21 ($channel:expr, $fmt:expr, $($arg:tt)*) => {
22 $crate::itm::write_fmt($channel, format_args!(concat!($fmt, "\n"), $($arg)*));
23 };
24}
25
26/// Macro to create a mutable reference to a statically allocated value
27///
28/// This macro returns a value with type `Option<&'static mut $ty>`. `Some($expr)` will be returned
29/// the first time the macro is executed; further calls will return `None`. To avoid `unwrap`ping a
30/// `None` variant the caller must ensure that the macro is called from a function that's executed
31/// at most once in the whole lifetime of the program.
32///
33/// # Notes
34/// This macro is unsound on multi core systems.
35///
36/// For debuggability, you can set an explicit name for a singleton. This name only shows up the
37/// the debugger and is not referencable from other code. See example below.
38///
39/// # Example
40///
41/// ``` no_run
42/// use cortex_m::singleton;
43///
44/// fn main() {
45/// // OK if `main` is executed only once
46/// let x: &'static mut bool = singleton!(: bool = false).unwrap();
47///
48/// let y = alias();
49/// // BAD this second call to `alias` will definitively `panic!`
50/// let y_alias = alias();
51/// }
52///
53/// fn alias() -> &'static mut bool {
54/// singleton!(: bool = false).unwrap()
55/// }
56///
57/// fn singleton_with_name() {
58/// // A name only for debugging purposes
59/// singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]);
60/// }
61/// ```
62#[macro_export]
63macro_rules! singleton {
64 ($name:ident: $ty:ty = $expr:expr) => {
65 $crate::interrupt::free(|_| {
66 // this is a tuple of a MaybeUninit and a bool because using an Option here is
67 // problematic: Due to niche-optimization, an Option could end up producing a non-zero
68 // initializer value which would move the entire static from `.bss` into `.data`...
69 static mut $name: (::core::mem::MaybeUninit<$ty>, bool) =
70 (::core::mem::MaybeUninit::uninit(), false);
71
72 #[allow(unsafe_code)]
73 let used = unsafe { $name.1 };
74 if used {
75 None
76 } else {
77 let expr = $expr;
78
79 #[allow(unsafe_code)]
80 unsafe {
81 $name.1 = true;
82 $name.0 = ::core::mem::MaybeUninit::new(expr);
83 Some(&mut *$name.0.as_mut_ptr())
84 }
85 }
86 })
87 };
88 (: $ty:ty = $expr:expr) => {
89 $crate::singleton!(VAR: $ty = $expr)
90 };
91}
92
93/// ``` compile_fail
94/// use cortex_m::singleton;
95///
96/// fn foo() {
97/// // check that the call to `uninitialized` requires unsafe
98/// singleton!(: u8 = std::mem::uninitialized());
99/// }
100/// ```
101#[allow(dead_code)]
102const CFAIL: () = ();
103
104/// ```
105/// #![deny(unsafe_code)]
106/// use cortex_m::singleton;
107///
108/// fn foo() {
109/// // check that calls to `singleton!` don't trip the `unsafe_code` lint
110/// singleton!(: u8 = 0);
111/// }
112/// ```
113#[allow(dead_code)]
114const CPASS: () = ();