diff options
| author | Ulf Lilleengen <[email protected]> | 2022-11-22 22:04:42 +0100 |
|---|---|---|
| committer | Ulf Lilleengen <[email protected]> | 2022-11-23 13:54:59 +0100 |
| commit | 04a7d976733e021395ff26e26dfa983e67b773a0 (patch) | |
| tree | c910e1015bbeb04ea26f1b53db5feb28827889d3 /embassy-macros | |
| parent | 2fa2c1a6fe9c79f11f7382a63ba6a13fe1bae1be (diff) | |
refactor: autodetect macro variant
Export all main macro per target architecture from embassy-macros,
and select the appropriate macro in embassy-executor.
Diffstat (limited to 'embassy-macros')
| -rw-r--r-- | embassy-macros/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-macros/src/lib.rs | 81 | ||||
| -rw-r--r-- | embassy-macros/src/macros/main.rs | 98 |
3 files changed, 129 insertions, 54 deletions
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml index 9b83771c8..5c612c997 100644 --- a/embassy-macros/Cargo.toml +++ b/embassy-macros/Cargo.toml | |||
| @@ -21,9 +21,5 @@ proc-macro2 = "1.0.29" | |||
| 21 | proc-macro = true | 21 | proc-macro = true |
| 22 | 22 | ||
| 23 | [features] | 23 | [features] |
| 24 | std = [] | ||
| 25 | wasm = [] | ||
| 26 | riscv = [] | ||
| 27 | |||
| 28 | # Enabling this cause interrupt::take! to require embassy-executor | 24 | # Enabling this cause interrupt::take! to require embassy-executor |
| 29 | rtos-trace-interrupt = [] | 25 | rtos-trace-interrupt = [] |
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index f5df2a269..d2c696c72 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs | |||
| @@ -45,7 +45,7 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 45 | task::run(args, f).unwrap_or_else(|x| x).into() | 45 | task::run(args, f).unwrap_or_else(|x| x).into() |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | /// Creates a new `executor` instance and declares an application entry point spawning the corresponding function body as an async task. | 48 | /// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task. |
| 49 | /// | 49 | /// |
| 50 | /// The following restrictions apply: | 50 | /// The following restrictions apply: |
| 51 | /// | 51 | /// |
| @@ -64,10 +64,85 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 64 | /// } | 64 | /// } |
| 65 | /// ``` | 65 | /// ``` |
| 66 | #[proc_macro_attribute] | 66 | #[proc_macro_attribute] |
| 67 | pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | 67 | pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { |
| 68 | let args = syn::parse_macro_input!(args as syn::AttributeArgs); | 68 | let args = syn::parse_macro_input!(args as syn::AttributeArgs); |
| 69 | let f = syn::parse_macro_input!(item as syn::ItemFn); | 69 | let f = syn::parse_macro_input!(item as syn::ItemFn); |
| 70 | main::run(args, f).unwrap_or_else(|x| x).into() | 70 | main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into() |
| 71 | } | ||
| 72 | |||
| 73 | /// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. | ||
| 74 | /// | ||
| 75 | /// The following restrictions apply: | ||
| 76 | /// | ||
| 77 | /// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks. | ||
| 78 | /// * The function must be declared `async`. | ||
| 79 | /// * The function must not use generics. | ||
| 80 | /// * Only a single `main` task may be declared. | ||
| 81 | /// | ||
| 82 | /// ## Examples | ||
| 83 | /// Spawning a task: | ||
| 84 | /// | ||
| 85 | /// ``` rust | ||
| 86 | /// #[embassy_executor::main] | ||
| 87 | /// async fn main(_s: embassy_executor::Spawner) { | ||
| 88 | /// // Function body | ||
| 89 | /// } | ||
| 90 | /// ``` | ||
| 91 | #[proc_macro_attribute] | ||
| 92 | pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream { | ||
| 93 | let args = syn::parse_macro_input!(args as syn::AttributeArgs); | ||
| 94 | let f = syn::parse_macro_input!(item as syn::ItemFn); | ||
| 95 | main::run(args, f, main::riscv()).unwrap_or_else(|x| x).into() | ||
| 96 | } | ||
| 97 | |||
| 98 | /// Creates a new `executor` instance and declares an application entry point for STD spawning the corresponding function body as an async task. | ||
| 99 | /// | ||
| 100 | /// The following restrictions apply: | ||
| 101 | /// | ||
| 102 | /// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks. | ||
| 103 | /// * The function must be declared `async`. | ||
| 104 | /// * The function must not use generics. | ||
| 105 | /// * Only a single `main` task may be declared. | ||
| 106 | /// | ||
| 107 | /// ## Examples | ||
| 108 | /// Spawning a task: | ||
| 109 | /// | ||
| 110 | /// ``` rust | ||
| 111 | /// #[embassy_executor::main] | ||
| 112 | /// async fn main(_s: embassy_executor::Spawner) { | ||
| 113 | /// // Function body | ||
| 114 | /// } | ||
| 115 | /// ``` | ||
| 116 | #[proc_macro_attribute] | ||
| 117 | pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { | ||
| 118 | let args = syn::parse_macro_input!(args as syn::AttributeArgs); | ||
| 119 | let f = syn::parse_macro_input!(item as syn::ItemFn); | ||
| 120 | main::run(args, f, main::std()).unwrap_or_else(|x| x).into() | ||
| 121 | } | ||
| 122 | |||
| 123 | /// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task. | ||
| 124 | /// | ||
| 125 | /// The following restrictions apply: | ||
| 126 | /// | ||
| 127 | /// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks. | ||
| 128 | /// * The function must be declared `async`. | ||
| 129 | /// * The function must not use generics. | ||
| 130 | /// * Only a single `main` task may be declared. | ||
| 131 | /// | ||
| 132 | /// ## Examples | ||
| 133 | /// Spawning a task: | ||
| 134 | /// | ||
| 135 | /// ``` rust | ||
| 136 | /// #[embassy_executor::main] | ||
| 137 | /// async fn main(_s: embassy_executor::Spawner) { | ||
| 138 | /// // Function body | ||
| 139 | /// } | ||
| 140 | /// ``` | ||
| 141 | #[proc_macro_attribute] | ||
| 142 | pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream { | ||
| 143 | let args = syn::parse_macro_input!(args as syn::AttributeArgs); | ||
| 144 | let f = syn::parse_macro_input!(item as syn::ItemFn); | ||
| 145 | main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into() | ||
| 71 | } | 146 | } |
| 72 | 147 | ||
| 73 | #[proc_macro_attribute] | 148 | #[proc_macro_attribute] |
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs index 54806847c..18f7c36c4 100644 --- a/embassy-macros/src/macros/main.rs +++ b/embassy-macros/src/macros/main.rs | |||
| @@ -7,31 +7,34 @@ use crate::util::ctxt::Ctxt; | |||
| 7 | #[derive(Debug, FromMeta)] | 7 | #[derive(Debug, FromMeta)] |
| 8 | struct Args {} | 8 | struct Args {} |
| 9 | 9 | ||
| 10 | pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> { | 10 | pub fn riscv() -> TokenStream { |
| 11 | #[allow(unused_variables)] | 11 | quote! { |
| 12 | let args = Args::from_list(&args).map_err(|e| e.write_errors())?; | 12 | #[riscv_rt::entry] |
| 13 | 13 | fn main() -> ! { | |
| 14 | let fargs = f.sig.inputs.clone(); | 14 | let mut executor = ::embassy_executor::Executor::new(); |
| 15 | 15 | let executor = unsafe { __make_static(&mut executor) }; | |
| 16 | let ctxt = Ctxt::new(); | 16 | executor.run(|spawner| { |
| 17 | 17 | spawner.must_spawn(__embassy_main(spawner)); | |
| 18 | if f.sig.asyncness.is_none() { | 18 | }) |
| 19 | ctxt.error_spanned_by(&f.sig, "main function must be async"); | 19 | } |
| 20 | } | ||
| 21 | if !f.sig.generics.params.is_empty() { | ||
| 22 | ctxt.error_spanned_by(&f.sig, "main function must not be generic"); | ||
| 23 | } | 20 | } |
| 21 | } | ||
| 24 | 22 | ||
| 25 | if fargs.len() != 1 { | 23 | pub fn cortex_m() -> TokenStream { |
| 26 | ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner."); | 24 | quote! { |
| 25 | #[cortex_m_rt::entry] | ||
| 26 | fn main() -> ! { | ||
| 27 | let mut executor = ::embassy_executor::Executor::new(); | ||
| 28 | let executor = unsafe { __make_static(&mut executor) }; | ||
| 29 | executor.run(|spawner| { | ||
| 30 | spawner.must_spawn(__embassy_main(spawner)); | ||
| 31 | }) | ||
| 32 | } | ||
| 27 | } | 33 | } |
| 34 | } | ||
| 28 | 35 | ||
| 29 | ctxt.check()?; | 36 | pub fn wasm() -> TokenStream { |
| 30 | 37 | quote! { | |
| 31 | let f_body = f.block; | ||
| 32 | |||
| 33 | #[cfg(feature = "wasm")] | ||
| 34 | let main = quote! { | ||
| 35 | #[wasm_bindgen::prelude::wasm_bindgen(start)] | 38 | #[wasm_bindgen::prelude::wasm_bindgen(start)] |
| 36 | pub fn main() -> Result<(), wasm_bindgen::JsValue> { | 39 | pub fn main() -> Result<(), wasm_bindgen::JsValue> { |
| 37 | static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new(); | 40 | static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new(); |
| @@ -43,10 +46,11 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke | |||
| 43 | 46 | ||
| 44 | Ok(()) | 47 | Ok(()) |
| 45 | } | 48 | } |
| 46 | }; | 49 | } |
| 50 | } | ||
| 47 | 51 | ||
| 48 | #[cfg(all(feature = "std", not(feature = "wasm"), not(feature = "riscv")))] | 52 | pub fn std() -> TokenStream { |
| 49 | let main = quote! { | 53 | quote! { |
| 50 | fn main() -> ! { | 54 | fn main() -> ! { |
| 51 | let mut executor = ::embassy_executor::Executor::new(); | 55 | let mut executor = ::embassy_executor::Executor::new(); |
| 52 | let executor = unsafe { __make_static(&mut executor) }; | 56 | let executor = unsafe { __make_static(&mut executor) }; |
| @@ -55,31 +59,31 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke | |||
| 55 | spawner.must_spawn(__embassy_main(spawner)); | 59 | spawner.must_spawn(__embassy_main(spawner)); |
| 56 | }) | 60 | }) |
| 57 | } | 61 | } |
| 58 | }; | 62 | } |
| 63 | } | ||
| 59 | 64 | ||
| 60 | #[cfg(all(not(feature = "std"), not(feature = "wasm"), not(feature = "riscv")))] | 65 | pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> { |
| 61 | let main = quote! { | 66 | #[allow(unused_variables)] |
| 62 | #[cortex_m_rt::entry] | 67 | let args = Args::from_list(&args).map_err(|e| e.write_errors())?; |
| 63 | fn main() -> ! { | ||
| 64 | let mut executor = ::embassy_executor::Executor::new(); | ||
| 65 | let executor = unsafe { __make_static(&mut executor) }; | ||
| 66 | executor.run(|spawner| { | ||
| 67 | spawner.must_spawn(__embassy_main(spawner)); | ||
| 68 | }) | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | 68 | ||
| 72 | #[cfg(all(not(feature = "std"), not(feature = "wasm"), feature = "riscv"))] | 69 | let fargs = f.sig.inputs.clone(); |
| 73 | let main = quote! { | 70 | |
| 74 | #[riscv_rt::entry] | 71 | let ctxt = Ctxt::new(); |
| 75 | fn main() -> ! { | 72 | |
| 76 | let mut executor = ::embassy_executor::Executor::new(); | 73 | if f.sig.asyncness.is_none() { |
| 77 | let executor = unsafe { __make_static(&mut executor) }; | 74 | ctxt.error_spanned_by(&f.sig, "main function must be async"); |
| 78 | executor.run(|spawner| { | 75 | } |
| 79 | spawner.must_spawn(__embassy_main(spawner)); | 76 | if !f.sig.generics.params.is_empty() { |
| 80 | }) | 77 | ctxt.error_spanned_by(&f.sig, "main function must not be generic"); |
| 81 | } | 78 | } |
| 82 | }; | 79 | |
| 80 | if fargs.len() != 1 { | ||
| 81 | ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner."); | ||
| 82 | } | ||
| 83 | |||
| 84 | ctxt.check()?; | ||
| 85 | |||
| 86 | let f_body = f.block; | ||
| 83 | 87 | ||
| 84 | let result = quote! { | 88 | let result = quote! { |
| 85 | #[::embassy_executor::task()] | 89 | #[::embassy_executor::task()] |
