Skip to content

Commit 422f232

Browse files
authored
Add assign_resources (#3809)
* Add assign_resources * Mark unstable
1 parent f9419af commit 422f232

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

esp-hal/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- A reimplemntation of the `assign_resources!` macro (#3809)
1213

1314
### Changed
1415

esp-hal/src/macros.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,155 @@ macro_rules! metadata {
315315
};
316316
};
317317
}
318+
319+
#[procmacros::doc_replace]
320+
/// Extract fields from [`Peripherals`][crate::peripherals::Peripherals] into named groups.
321+
///
322+
/// ## Example
323+
///
324+
/// ```rust,no_run
325+
/// # {before_snippet}
326+
/// #
327+
/// use esp_hal::assign_resources;
328+
///
329+
/// assign_resources! {
330+
/// Resources<'d> {
331+
/// display: DisplayResources<'d> {
332+
/// spi: SPI2,
333+
/// sda: GPIO6,
334+
/// sclk: GPIO7,
335+
/// cs: GPIO8,
336+
/// dc: GPIO9,
337+
/// },
338+
/// axl: AccelerometerResources<'d> {
339+
/// i2c: I2C0,
340+
/// sda: GPIO12,
341+
/// scl: GPIO13,
342+
/// },
343+
/// }
344+
/// }
345+
///
346+
/// # struct Display<'d>(core::marker::PhantomData<&'d ()>);
347+
/// fn init_display<'d>(r: DisplayResources<'d>) -> Display<'d> {
348+
/// // use `r.spi`, `r.sda`, `r.sclk`, `r.cs`, `r.dc`
349+
/// todo!()
350+
/// }
351+
///
352+
/// # struct Accelerometer<'d>(core::marker::PhantomData<&'d ()>);
353+
/// fn init_accelerometer<'d>(r: AccelerometerResources<'d>) -> Accelerometer<'d> {
354+
/// // use `r.i2c`, `r.sda`, `r.scl`
355+
/// todo!()
356+
/// }
357+
///
358+
/// // let peripherals = esp_hal::init(...);
359+
/// let resources = split_resources!(peripherals);
360+
///
361+
/// let display = init_display(resources.display);
362+
/// let axl = init_accelerometer(resources.axl);
363+
///
364+
/// // Other fields (`peripherals.UART0`, ...) of the `peripherals` struct can still be accessed.
365+
/// # {after_snippet}
366+
/// ```
367+
// Based on https://crates.io/crates/assign-resources
368+
#[macro_export]
369+
#[cfg(feature = "unstable")]
370+
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
371+
macro_rules! assign_resources {
372+
{
373+
$(#[$struct_meta:meta])*
374+
$vis:vis $struct_name:ident<$struct_lt:lifetime> {
375+
$(
376+
$(#[$group_meta:meta])*
377+
$group_name:ident : $group_struct:ident<$group_lt:lifetime> {
378+
$(
379+
$(#[$resource_meta:meta])*
380+
$resource_name:ident : $resource_field:ident
381+
),*
382+
$(,)?
383+
}
384+
),+
385+
$(,)?
386+
}
387+
} => {
388+
// Group structs
389+
$(
390+
$(#[$group_meta])*
391+
#[allow(missing_docs)]
392+
$vis struct $group_struct<$group_lt> {
393+
$(
394+
$(#[$resource_meta])*
395+
pub $resource_name: $crate::peripherals::$resource_field<$group_lt>,
396+
)+
397+
}
398+
399+
impl<$group_lt> $group_struct<$group_lt> {
400+
/// Unsafely create an instance of the assigned peripherals out of thin air.
401+
///
402+
/// # Safety
403+
///
404+
/// You must ensure that you're only using one instance of the contained peripherals at a time.
405+
pub unsafe fn steal() -> Self {
406+
unsafe {
407+
Self {
408+
$($resource_name: $crate::peripherals::$resource_field::steal()),*
409+
}
410+
}
411+
}
412+
413+
/// Creates a new reference to the peripheral group with a shorter lifetime.
414+
///
415+
/// Use this method if you would like to keep working with the peripherals after
416+
/// you dropped the drivers that consume this.
417+
pub fn reborrow(&mut self) -> $group_struct<'_> {
418+
$group_struct {
419+
$($resource_name: self.$resource_name.reborrow()),*
420+
}
421+
}
422+
}
423+
)+
424+
425+
// Outer struct
426+
$(#[$struct_meta])*
427+
/// Assigned resources.
428+
$vis struct $struct_name<$struct_lt> {
429+
$( pub $group_name: $group_struct<$struct_lt>, )+
430+
}
431+
432+
impl<$struct_lt> $struct_name<$struct_lt> {
433+
/// Unsafely create an instance of the assigned peripherals out of thin air.
434+
///
435+
/// # Safety
436+
///
437+
/// You must ensure that you're only using one instance of the contained peripherals at a time.
438+
pub unsafe fn steal() -> Self {
439+
unsafe {
440+
Self {
441+
$($group_name: $group_struct::steal()),*
442+
}
443+
}
444+
}
445+
446+
/// Creates a new reference to the assigned peripherals with a shorter lifetime.
447+
///
448+
/// Use this method if you would like to keep working with the peripherals after
449+
/// you dropped the drivers that consume this.
450+
pub fn reborrow(&mut self) -> $struct_name<'_> {
451+
$struct_name {
452+
$($group_name: self.$group_name.reborrow()),*
453+
}
454+
}
455+
}
456+
457+
/// Extracts resources from the `Peripherals` struct.
458+
#[macro_export]
459+
macro_rules! split_resources {
460+
($peris:ident) => {
461+
$struct_name {
462+
$($group_name: $group_struct {
463+
$($resource_name: $peris.$resource_field),*
464+
}),*
465+
}
466+
}
467+
}
468+
};
469+
}

0 commit comments

Comments
 (0)