aboutsummaryrefslogtreecommitdiff
path: root/embassy-macros
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2022-11-22 22:04:42 +0100
committerUlf Lilleengen <[email protected]>2022-11-23 13:54:59 +0100
commit04a7d976733e021395ff26e26dfa983e67b773a0 (patch)
treec910e1015bbeb04ea26f1b53db5feb28827889d3 /embassy-macros
parent2fa2c1a6fe9c79f11f7382a63ba6a13fe1bae1be (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.toml4
-rw-r--r--embassy-macros/src/lib.rs81
-rw-r--r--embassy-macros/src/macros/main.rs98
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"
21proc-macro = true 21proc-macro = true
22 22
23[features] 23[features]
24std = []
25wasm = []
26riscv = []
27
28# Enabling this cause interrupt::take! to require embassy-executor 24# Enabling this cause interrupt::take! to require embassy-executor
29rtos-trace-interrupt = [] 25rtos-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]
67pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { 67pub 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]
92pub 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]
117pub 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]
142pub 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)]
8struct Args {} 8struct Args {}
9 9
10pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> { 10pub 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 { 23pub 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()?; 36pub 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")))] 52pub 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")))] 65pub 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()]