mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-28 21:01:06 +00:00
Merge pull request #4046 from outfoxxed/main-macro-executor
executor: add executor selection to #[embassy_executor::main]
This commit is contained in:
commit
1eec964637
@ -173,3 +173,27 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
main::run(args.into(), item.into(), &main::ARCH_WASM).into()
|
main::run(args.into(), item.into(), &main::ARCH_WASM).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `executor` instance and declares an application entry point for an unspecified architecture, spawning the corresponding function body as an async task.
|
||||||
|
///
|
||||||
|
/// The following restrictions apply:
|
||||||
|
///
|
||||||
|
/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
|
||||||
|
/// * The function must be declared `async`.
|
||||||
|
/// * The function must not use generics.
|
||||||
|
/// * Only a single `main` task may be declared.
|
||||||
|
///
|
||||||
|
/// A user-defined entry macro and executor type must be provided via the `entry` and `executor` arguments of the `main` macro.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
/// Spawning a task:
|
||||||
|
/// ``` rust
|
||||||
|
/// #[embassy_executor::main(entry = "your_hal::entry", executor = "your_hal::Executor")]
|
||||||
|
/// async fn main(_s: embassy_executor::Spawner) {
|
||||||
|
/// // Function body
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn main_unspecified(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
main::run(args.into(), item.into(), &main::ARCH_UNSPECIFIED).into()
|
||||||
|
}
|
||||||
|
@ -16,42 +16,57 @@ enum Flavor {
|
|||||||
pub(crate) struct Arch {
|
pub(crate) struct Arch {
|
||||||
default_entry: Option<&'static str>,
|
default_entry: Option<&'static str>,
|
||||||
flavor: Flavor,
|
flavor: Flavor,
|
||||||
|
executor_required: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static ARCH_AVR: Arch = Arch {
|
pub static ARCH_AVR: Arch = Arch {
|
||||||
default_entry: Some("avr_device::entry"),
|
default_entry: Some("avr_device::entry"),
|
||||||
flavor: Flavor::Standard,
|
flavor: Flavor::Standard,
|
||||||
|
executor_required: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static ARCH_RISCV: Arch = Arch {
|
pub static ARCH_RISCV: Arch = Arch {
|
||||||
default_entry: Some("riscv_rt::entry"),
|
default_entry: Some("riscv_rt::entry"),
|
||||||
flavor: Flavor::Standard,
|
flavor: Flavor::Standard,
|
||||||
|
executor_required: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static ARCH_CORTEX_M: Arch = Arch {
|
pub static ARCH_CORTEX_M: Arch = Arch {
|
||||||
default_entry: Some("cortex_m_rt::entry"),
|
default_entry: Some("cortex_m_rt::entry"),
|
||||||
flavor: Flavor::Standard,
|
flavor: Flavor::Standard,
|
||||||
|
executor_required: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static ARCH_SPIN: Arch = Arch {
|
pub static ARCH_SPIN: Arch = Arch {
|
||||||
default_entry: None,
|
default_entry: None,
|
||||||
flavor: Flavor::Standard,
|
flavor: Flavor::Standard,
|
||||||
|
executor_required: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static ARCH_STD: Arch = Arch {
|
pub static ARCH_STD: Arch = Arch {
|
||||||
default_entry: None,
|
default_entry: None,
|
||||||
flavor: Flavor::Standard,
|
flavor: Flavor::Standard,
|
||||||
|
executor_required: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static ARCH_WASM: Arch = Arch {
|
pub static ARCH_WASM: Arch = Arch {
|
||||||
default_entry: Some("wasm_bindgen::prelude::wasm_bindgen(start)"),
|
default_entry: Some("wasm_bindgen::prelude::wasm_bindgen(start)"),
|
||||||
flavor: Flavor::Wasm,
|
flavor: Flavor::Wasm,
|
||||||
|
executor_required: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static ARCH_UNSPECIFIED: Arch = Arch {
|
||||||
|
default_entry: None,
|
||||||
|
flavor: Flavor::Standard,
|
||||||
|
executor_required: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, FromMeta, Default)]
|
#[derive(Debug, FromMeta, Default)]
|
||||||
struct Args {
|
struct Args {
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
entry: Option<String>,
|
entry: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
|
executor: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
|
pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
|
||||||
@ -112,9 +127,10 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
|
|||||||
error(&mut errors, &f.sig, "main function must have 1 argument: the spawner.");
|
error(&mut errors, &f.sig, "main function must have 1 argument: the spawner.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = match args.entry.as_deref().or(arch.default_entry) {
|
let entry = match (args.entry.as_deref(), arch.default_entry.as_deref()) {
|
||||||
None => TokenStream::new(),
|
(None, None) => TokenStream::new(),
|
||||||
Some(x) => match TokenStream::from_str(x) {
|
(Some(x), _) | (None, Some(x)) if x == "" => TokenStream::new(),
|
||||||
|
(Some(x), _) | (None, Some(x)) => match TokenStream::from_str(x) {
|
||||||
Ok(x) => quote!(#[#x]),
|
Ok(x) => quote!(#[#x]),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error(&mut errors, &f.sig, e);
|
error(&mut errors, &f.sig, e);
|
||||||
@ -123,6 +139,28 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let executor = match (args.executor.as_deref(), arch.executor_required) {
|
||||||
|
(None, true) => {
|
||||||
|
error(
|
||||||
|
&mut errors,
|
||||||
|
&f.sig,
|
||||||
|
"\
|
||||||
|
No architecture selected for embassy-executor. Make sure you've enabled one of the `arch-*` features in your Cargo.toml.
|
||||||
|
|
||||||
|
Alternatively, if you would like to use a custom executor implementation, specify it with the `executor` argument.
|
||||||
|
For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Executor\")]",
|
||||||
|
);
|
||||||
|
""
|
||||||
|
}
|
||||||
|
(Some(x), _) => x,
|
||||||
|
(None, _) => "::embassy_executor::Executor",
|
||||||
|
};
|
||||||
|
|
||||||
|
let executor = TokenStream::from_str(executor).unwrap_or_else(|e| {
|
||||||
|
error(&mut errors, &f.sig, e);
|
||||||
|
TokenStream::new()
|
||||||
|
});
|
||||||
|
|
||||||
let f_body = f.body;
|
let f_body = f.body;
|
||||||
let out = &f.sig.output;
|
let out = &f.sig.output;
|
||||||
|
|
||||||
@ -134,7 +172,7 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
|
|||||||
::core::mem::transmute(t)
|
::core::mem::transmute(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut executor = ::embassy_executor::Executor::new();
|
let mut executor = #executor::new();
|
||||||
let executor = unsafe { __make_static(&mut executor) };
|
let executor = unsafe { __make_static(&mut executor) };
|
||||||
executor.run(|spawner| {
|
executor.run(|spawner| {
|
||||||
spawner.must_spawn(__embassy_main(spawner));
|
spawner.must_spawn(__embassy_main(spawner));
|
||||||
@ -144,7 +182,7 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
|
|||||||
Flavor::Wasm => (
|
Flavor::Wasm => (
|
||||||
quote!(Result<(), wasm_bindgen::JsValue>),
|
quote!(Result<(), wasm_bindgen::JsValue>),
|
||||||
quote! {
|
quote! {
|
||||||
let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
|
let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(#executor::new()));
|
||||||
|
|
||||||
executor.start(|spawner| {
|
executor.start(|spawner| {
|
||||||
spawner.must_spawn(__embassy_main(spawner));
|
spawner.must_spawn(__embassy_main(spawner));
|
||||||
|
@ -44,6 +44,8 @@ mod arch;
|
|||||||
#[cfg(feature = "_arch")]
|
#[cfg(feature = "_arch")]
|
||||||
#[allow(unused_imports)] // don't warn if the module is empty.
|
#[allow(unused_imports)] // don't warn if the module is empty.
|
||||||
pub use arch::*;
|
pub use arch::*;
|
||||||
|
#[cfg(not(feature = "_arch"))]
|
||||||
|
pub use embassy_executor_macros::main_unspecified as main;
|
||||||
|
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user