esp_hal/
macros.rs

1//! Macros used by the HAL.
2//!
3//! Most of the macros in this module are hidden and intended for internal use
4//! only. For the list of public macros, see the [procmacros](https://docs.rs/esp-hal-procmacros/latest/esp_hal_procmacros/)
5//! documentation.
6#[doc(hidden)]
7/// Helper macro for checking doctest code snippets
8#[macro_export]
9macro_rules! before_snippet {
10    () => {
11        r#"
12# #![no_std]
13# use procmacros::handler;
14# use esp_hal::{interrupt::{self, InterruptConfigurable}, time::{Duration, Instant, Rate}};
15# macro_rules! println {
16#     ($($tt:tt)*) => { };
17# }
18# macro_rules! print {
19#     ($($tt:tt)*) => { };
20# }
21# #[panic_handler]
22# fn panic(_ : &core::panic::PanicInfo) -> ! {
23#     loop {}
24# }
25# fn main() {
26#   let _ = example();
27# }
28# struct ExampleError {}
29# impl <T> From<T> for ExampleError where T: core::fmt::Debug {
30#   fn from(_value: T) -> Self {
31#       Self{}
32#   }
33# }
34# fn example() -> Result<(), ExampleError> {
35#   let mut peripherals = esp_hal::init(esp_hal::Config::default());
36"#
37    };
38}
39
40#[doc(hidden)]
41#[macro_export]
42macro_rules! trm_markdown_link {
43    () => {
44        concat!("[Technical Reference Manual](", $crate::trm_link!(), ")")
45    };
46    ($anchor:literal) => {
47        concat!(
48            "[Technical Reference Manual](",
49            $crate::trm_link!(),
50            "#",
51            $anchor,
52            ")"
53        )
54    };
55}
56
57#[doc(hidden)]
58/// Shorthand to define enums with From implementations.
59#[macro_export]
60macro_rules! any_enum {
61    ($(#[$meta:meta])* $vis:vis enum $name:ident {
62        $(
63            $(#[$variant_meta:meta])*
64            $variant:ident($inner:ty)
65        ),* $(,)?
66    }) => {
67        $(#[$meta])*
68        $vis enum $name {
69            $(
70                $(#[$variant_meta])*
71                $variant($inner),
72            )*
73        }
74
75        $(
76            $(#[$variant_meta])*
77            impl From<$inner> for $name {
78                fn from(inner: $inner) -> Self {
79                    $name::$variant(inner)
80                }
81            }
82        )*
83    };
84}
85
86#[doc(hidden)]
87/// Shorthand to define AnyPeripheral instances.
88///
89/// This macro generates the following:
90///
91/// - An `AnyPeripheral` struct, name provided by the macro call.
92/// - An `AnyPeripheralInner` enum, with the same variants as the original
93///   peripheral.
94/// - A `From` implementation for each peripheral variant.
95/// - A `degrade` method for each peripheral variant using the
96///   `IntoAnyPeripheral` trait.
97#[macro_export]
98macro_rules! any_peripheral {
99    ($(#[$meta:meta])* $vis:vis peripheral $name:ident<'d> {
100        $(
101            $(#[cfg($variant_meta:meta)])*
102            $variant:ident($inner:ty)
103        ),* $(,)?
104    }) => {
105        paste::paste! {
106            $(#[$meta])*
107            ///
108            /// This struct is a type-erased version of a peripheral singleton. It is useful
109            /// for creating arrays of peripherals, or avoiding generics. Peripheral singletons
110            /// can be type erased by using their `From` implementation.
111            ///
112            /// ```rust,ignore
113            #[doc = concat!("let any_peripheral = ", stringify!($name), "::from(peripheral);")]
114            /// ```
115            #[derive(Debug)]
116            #[cfg_attr(feature = "defmt", derive(defmt::Format))]
117            $vis struct $name<'d>([< $name Inner >]<'d>);
118
119            impl $name<'_> {
120                /// Unsafely clone this peripheral reference.
121                ///
122                /// # Safety
123                ///
124                /// You must ensure that you're only using one instance of this type at a time.
125                #[inline]
126                pub unsafe fn clone_unchecked(&self) -> Self { unsafe {
127                    match &self.0 {
128                        $(
129                            $(#[cfg($variant_meta)])*
130                            [< $name Inner >]::$variant(inner) => $name([<$name Inner>]::$variant(inner.clone_unchecked())),
131                        )*
132                    }
133                }}
134
135                /// Creates a new peripheral reference with a shorter lifetime.
136                ///
137                /// Use this method if you would like to keep working with the peripheral after
138                /// you dropped the driver that consumes this.
139                #[inline]
140                pub fn reborrow(&mut self) -> $name<'_> {
141                    unsafe { self.clone_unchecked() }
142                }
143            }
144
145            impl $crate::private::Sealed for $name<'_> {}
146
147            $(#[$meta])*
148            #[derive(Debug)]
149            enum [< $name Inner >]<'d> {
150                $(
151                    $(#[cfg($variant_meta)])*
152                    $variant($inner),
153                )*
154            }
155
156            #[cfg(feature = "defmt")]
157            impl defmt::Format for [< $name Inner >]<'_> {
158                fn format(&self, fmt: defmt::Formatter<'_>) {
159                    match self {
160                        $(
161                            $(#[cfg($variant_meta)])*
162                            [< $name Inner >]::$variant(inner) => inner.format(fmt),
163                        )*
164                    }
165                }
166            }
167
168            // Trick to make peripherals implement Into, without
169            // requiring Instance traits to have lifetimes.
170            #[doc(hidden)]
171            pub trait [<Into $name>]: Sized + $crate::private::Sealed {
172                fn degrade<'a>(self) -> $name<'a>
173                where
174                    Self: 'a;
175            }
176
177            // AnyPeripheral converts into itself
178            impl<'d> [<Into $name>] for $name<'d> {
179                #[inline]
180                fn degrade<'a>(self) -> $name<'a>
181                where
182                    Self: 'a,
183                {
184                    self
185                }
186            }
187
188            $(
189                // Variants convert into AnyPeripheral
190                $(#[cfg($variant_meta)])*
191                impl<'d> [<Into $name>] for $inner {
192                    #[inline]
193                    fn degrade<'a>(self) -> $name<'a>
194                    where
195                        Self: 'a,
196                    {
197                        $name::from(self)
198                    }
199                }
200
201                $(#[cfg($variant_meta)])*
202                impl<'d> From<$inner> for $name<'d> {
203                    #[inline]
204                    fn from(inner: $inner) -> Self {
205                        Self([< $name Inner >]::$variant(inner))
206                    }
207                }
208            )*
209        }
210    };
211}
212
213/// Macro to choose between two expressions. Useful for implementing "else" for
214/// `$()?` macro syntax.
215#[macro_export]
216#[doc(hidden)]
217macro_rules! if_set {
218    (, $not_set:expr) => {
219        $not_set
220    };
221    ($set:expr, $not_set:expr) => {
222        $set
223    };
224}
225
226/// Macro to ignore tokens.
227///
228/// This is useful when we need existence of a metavariable (to expand a
229/// repetition), but we don't need to use it.
230#[macro_export]
231#[doc(hidden)]
232macro_rules! ignore {
233    ($($item:tt)*) => {};
234}
235
236/// Define a piece of (Espressif-specific) metadata that external tools may
237/// parse.
238///
239/// The symbol name be formatted as `_ESP_METADATA_<category>_<name>`.
240///
241/// This metadata is zero cost, i.e. the value will not be flashed to the
242/// device.
243#[macro_export]
244#[doc(hidden)]
245macro_rules! metadata {
246    ($category:literal, $key:ident, $value:expr) => {
247        #[unsafe(link_section = concat!(".espressif.metadata"))]
248        #[used]
249        #[unsafe(export_name = concat!($category, ".", stringify!($key)))]
250        static $key: [u8; $value.len()] = const {
251            let val_bytes = $value.as_bytes();
252            let mut val_bytes_array = [0; $value.len()];
253            let mut i = 0;
254            while i < val_bytes.len() {
255                val_bytes_array[i] = val_bytes[i];
256                i += 1;
257            }
258            val_bytes_array
259        };
260    };
261}