Can this be simplified?

Hi, I want to work at some code and I want to simplify it because it is really verbose and repetitive.

Can this be simplified and more generic?

I would use a macro. Declarative macros are perfect for places where you would otherwise to copy/paste a chunk of code multiple times and only tweak one or two names.

1 Like

Thanks, but I have never programmed a macro before, so I have no clue where to start. Can you give me a hint?

Tried something like this.

#[macro_export]
macro_rules! avr {
    ( $( $x:expr ),* ) => {
        #[cfg(feature = "$x")]
        pub mod $x;

        #[cfg(feature = "$x")]
        impl $x::Peripherals {
            /// Returns all the peripherals *once*
            #[inline]
            pub fn take() -> Option<Self> {
                crate::interrupt::free(|_| {
                    if unsafe { DEVICE_PERIPHERALS } {
                        None
                    } else {
                        Some(unsafe { $x::Peripherals::steal() })
                    }
                })
            }
        }
    };
}

But is this correct? And how do I use it?

Try something like

macro_rules! peripherals {
    ($(
        $(#[$doc_comments:meta])*
        $name:ident $feature:literal
    )*) => {
        $(
            $(#[$doc_comments])*
            #[cfg(feature = $feature)]
            pub mod $name;

            #[cfg(feature = $feature)]
            impl $name::Peripherals {
                /// Returns all the peripherals *once*
                #[inline]
                pub fn take() -> Option<Self> {
                    crate::interrupt::free(|_| {
                        if unsafe { DEVICE_PERIPHERALS } {
                            None
                        } else {
                            Some(unsafe { $name::Peripherals::steal() })
                        }
                    })
                }
            }
        )*
    }
}

peripherals! {
    /// [AT90USB1286](https://www.microchip.com/wwwproducts/en/AT90USB1286)
    at90usb1286 "at90usb1286"

    /// [ATmega1280](https://www.microchip.com/wwwproducts/en/ATmega1280)
    atmega1280 "atmega1280"

    // etc...
}
2 Likes

Or with the paste crate, this could be simplified [1] to something like

macro_rules! peripherals {
    ($(
        $name:ident
    )*) => {
        paste::paste!{$(
            #[doc = " [" $name "](https://www.microchip.com/wwwproducts/en/" $name ")"]
            #[cfg(feature = $name:lower)]
            pub mod [<$name:lower>];

            #[cfg(feature = $name:lower)]
            impl [<$name:lower>]::Peripherals {
                /// Returns all the peripherals *once*
                #[inline]
                pub fn take() -> Option<Self> {
                    crate::interrupt::free(|_| {
                        if unsafe { DEVICE_PERIPHERALS } {
                            None
                        } else {
                            Some(unsafe { [<$name:lower>]::Peripherals::steal() })
                        }
                    })
                }
            }
        )*}
    }
}

peripherals! {
    AT90USB1286
    ATmega1280
    // etc...
}

  1. well… the macro definition becomes more complicated, but the macro call in the end is what’s simplified ↩︎

5 Likes

Thank you very much. I will try this as soon as possible and give you feedback. Than I will try to understand the code and how it works because currently I have no clue.

If you are feeling uncertain about how macros work, check out the Macros chapter from The Book for a basic introduction. After you feel like you grasp the basics, check out The Little Book of Rust Macros for some more advanced techniques and applications.

3 Likes

@MarkuBu also beyond the introduction in the book, for a more complete overview of everything that macro_rules macros technically support / can offer, see Macros By Example - The Rust Reference

Particularly useful: the list of “fragment specifiers”.

For the example involving paste, of course the documentation of the paste crate is useful.

Another important aspect to understand the macros I wrote: Doc comments

/// Some contents
/// here, documenting stuff!

are equivalent to (and desugared very early in compilation into) a sequence of doc attributes

#[doc = " Some contents"]
#[doc = " here, documenting stuff!"]

And for the paste code, it’s important to note this section, and apparently (maybe undocumented) the paste macro handles arguments to attributes other than doc = similarly, e.g. used for the #[cfg(feature = …)] attributes.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.