aboutsummaryrefslogtreecommitdiff
path: root/src/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/macros.rs')
-rw-r--r--src/macros.rs114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..512c932
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,114 @@
+/// Macro for sending a formatted string through an ITM channel
+#[macro_export]
+macro_rules! iprint {
+ ($channel:expr, $s:expr) => {
+ $crate::itm::write_str($channel, $s);
+ };
+ ($channel:expr, $($arg:tt)*) => {
+ $crate::itm::write_fmt($channel, format_args!($($arg)*));
+ };
+}
+
+/// Macro for sending a formatted string through an ITM channel, with a newline.
+#[macro_export]
+macro_rules! iprintln {
+ ($channel:expr) => {
+ $crate::itm::write_str($channel, "\n");
+ };
+ ($channel:expr, $fmt:expr) => {
+ $crate::itm::write_str($channel, concat!($fmt, "\n"));
+ };
+ ($channel:expr, $fmt:expr, $($arg:tt)*) => {
+ $crate::itm::write_fmt($channel, format_args!(concat!($fmt, "\n"), $($arg)*));
+ };
+}
+
+/// 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.
+///
+/// # Notes
+/// This macro is unsound on multi core systems.
+///
+/// For debuggability, you can set an explicit name for a singleton. This name only shows up the
+/// the debugger and is not referencable from other code. See example below.
+///
+/// # Example
+///
+/// ``` no_run
+/// use cortex_m::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()
+/// }
+///
+/// fn singleton_with_name() {
+/// // A name only for debugging purposes
+/// singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]);
+/// }
+/// ```
+#[macro_export]
+macro_rules! singleton {
+ ($name:ident: $ty:ty = $expr:expr) => {
+ $crate::interrupt::free(|_| {
+ // this is a tuple of a MaybeUninit and a bool because using an Option here is
+ // problematic: Due to niche-optimization, an Option could end up producing a non-zero
+ // initializer value which would move the entire static from `.bss` into `.data`...
+ static mut $name: (::core::mem::MaybeUninit<$ty>, bool) =
+ (::core::mem::MaybeUninit::uninit(), false);
+
+ #[allow(unsafe_code)]
+ let used = unsafe { $name.1 };
+ if used {
+ None
+ } else {
+ let expr = $expr;
+
+ #[allow(unsafe_code)]
+ unsafe {
+ $name.1 = true;
+ $name.0 = ::core::mem::MaybeUninit::new(expr);
+ Some(&mut *$name.0.as_mut_ptr())
+ }
+ }
+ })
+ };
+ (: $ty:ty = $expr:expr) => {
+ $crate::singleton!(VAR: $ty = $expr)
+ };
+}
+
+/// ``` compile_fail
+/// use cortex_m::singleton;
+///
+/// fn foo() {
+/// // check that the call to `uninitialized` requires unsafe
+/// singleton!(: u8 = std::mem::uninitialized());
+/// }
+/// ```
+#[allow(dead_code)]
+const CFAIL: () = ();
+
+/// ```
+/// #![deny(unsafe_code)]
+/// use cortex_m::singleton;
+///
+/// fn foo() {
+/// // check that calls to `singleton!` don't trip the `unsafe_code` lint
+/// singleton!(: u8 = 0);
+/// }
+/// ```
+#[allow(dead_code)]
+const CPASS: () = ();