-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(config): add a
config
attribute macro
This attribute macro allows to register specific functions for customizing the initial driver setup.
- Loading branch information
1 parent
eb9c8ad
commit 04f864d
Showing
12 changed files
with
322 additions
and
150 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/// Register the function this attribute macro is applied on to provide the configuration for the | ||
/// associated driver during initial system configuration. | ||
/// | ||
/// The name of the function does not matter as it will be renamed by the macro. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - The name of the driver the function provides configuration for. | ||
/// | ||
/// | Driver | Expected return type | | ||
/// | --------- | ------------------------------ | | ||
/// | `network` | `embassy_net::Config` | | ||
/// | `usb` | `embassy_usb::Config<'static>` | | ||
/// | ||
/// # Note | ||
/// | ||
/// The `riot_rs` crate provides re-exports for the relevant Embassy crates. | ||
/// | ||
/// # Examples | ||
/// | ||
/// The following function provides configuration for the network stack: | ||
/// | ||
/// ```ignore | ||
/// use riot_rs::embassy_net; | ||
/// | ||
/// #[riot_rs::config(network)] | ||
/// fn network_config() -> embassy_net::Config { | ||
/// use embassy_net::Ipv4Address; | ||
/// | ||
/// embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { | ||
/// address: embassy_net::Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | ||
/// dns_servers: heapless::Vec::new(), | ||
/// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | ||
/// }) | ||
/// } | ||
/// ``` | ||
#[allow(clippy::missing_panics_doc)] | ||
#[proc_macro_attribute] | ||
pub fn config(args: TokenStream, item: TokenStream) -> TokenStream { | ||
use quote::{format_ident, quote}; | ||
|
||
let mut attrs = ConfigAttributes::default(); | ||
let thread_parser = syn::meta::parser(|meta| attrs.parse(&meta)); | ||
syn::parse_macro_input!(args with thread_parser); | ||
|
||
let config_function = syn::parse_macro_input!(item as syn::ItemFn); | ||
let config_function_name = &config_function.sig.ident; | ||
|
||
let riot_rs_crate = utils::riot_rs_crate(); | ||
|
||
let (config_fn_name, return_type) = match attrs.kind { | ||
Some(ConfigKind::Network) => ( | ||
format_ident!("riot_rs_network_config"), | ||
quote! {#riot_rs_crate::embassy::embassy_net::Config}, | ||
), | ||
Some(ConfigKind::Usb) => ( | ||
format_ident!("riot_rs_usb_config"), | ||
quote! {#riot_rs_crate::embassy::embassy_usb::Config<'static>}, | ||
), | ||
None => { | ||
panic!("a configuration kind must be specified"); | ||
} | ||
}; | ||
|
||
// Place the provided function into another function whose type signature we enforce. | ||
// This is important as that function will be called unsafely via FFI. | ||
let expanded = quote! { | ||
#[no_mangle] | ||
fn #config_fn_name() -> #return_type { | ||
#[inline(always)] | ||
#config_function | ||
|
||
#config_function_name() | ||
} | ||
}; | ||
|
||
TokenStream::from(expanded) | ||
} | ||
|
||
#[derive(Default)] | ||
struct ConfigAttributes { | ||
kind: Option<ConfigKind>, | ||
} | ||
|
||
impl ConfigAttributes { | ||
fn parse(&mut self, meta: &syn::meta::ParseNestedMeta) -> syn::Result<()> { | ||
use enum_iterator::all; | ||
|
||
for (config_name, kind) in all::<ConfigKind>().map(|c| (c.as_name(), c)) { | ||
if meta.path.is_ident(config_name) { | ||
self.check_only_one_kind(config_name); | ||
self.kind = Some(kind); | ||
return Ok(()); | ||
} | ||
} | ||
|
||
let supported_params = all::<ConfigKind>() | ||
.map(|c| format!("`{}`", c.as_name())) | ||
.collect::<Vec<_>>() | ||
.join(", "); | ||
Err(meta.error(format!( | ||
"unsupported parameter ({supported_params} are supported)", | ||
))) | ||
} | ||
|
||
fn check_only_one_kind(&self, param: &str) { | ||
assert!( | ||
self.kind.is_none(), | ||
"a separate function is required for `{param}` configuration", | ||
); | ||
} | ||
} | ||
|
||
#[derive(Debug, enum_iterator::Sequence)] | ||
enum ConfigKind { | ||
Network, | ||
Usb, | ||
} | ||
|
||
impl ConfigKind { | ||
fn as_name(&self) -> &'static str { | ||
match self { | ||
Self::Network => "network", | ||
Self::Usb => "usb", | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
#![deny(clippy::pedantic)] | ||
|
||
mod utils; | ||
|
||
use proc_macro::TokenStream; | ||
|
||
include!("config.rs"); | ||
include!("thread.rs"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
use quote::format_ident; | ||
|
||
const RIOT_RS_CRATE_NAME: &str = "riot-rs"; | ||
|
||
pub fn riot_rs_crate() -> syn::Ident { | ||
let riot_rs_crate = proc_macro_crate::crate_name(RIOT_RS_CRATE_NAME) | ||
.unwrap_or_else(|_| panic!("{RIOT_RS_CRATE_NAME} should be present in `Cargo.toml`")); | ||
|
||
match riot_rs_crate { | ||
proc_macro_crate::FoundCrate::Itself => { | ||
panic!( | ||
"{} cannot be used as a dependency of itself", | ||
env!("CARGO_CRATE_NAME"), | ||
); | ||
} | ||
proc_macro_crate::FoundCrate::Name(riot_rs_crate) => format_ident!("{}", riot_rs_crate), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters