aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor-macros/src/macros/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor-macros/src/macros/main.rs')
-rw-r--r--embassy-executor-macros/src/macros/main.rs240
1 files changed, 119 insertions, 121 deletions
diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs
index 66a3965d0..14b1d9de2 100644
--- a/embassy-executor-macros/src/macros/main.rs
+++ b/embassy-executor-macros/src/macros/main.rs
@@ -1,152 +1,107 @@
1use std::str::FromStr;
2
1use darling::export::NestedMeta; 3use darling::export::NestedMeta;
2use darling::{Error, FromMeta}; 4use darling::FromMeta;
3use proc_macro2::TokenStream; 5use proc_macro2::TokenStream;
4use quote::quote; 6use quote::quote;
5use syn::{Expr, ReturnType, Type}; 7use syn::{ReturnType, Type};
8
9use crate::util::*;
10
11enum Flavor {
12 Standard,
13 Wasm,
14}
6 15
7use crate::util::ctxt::Ctxt; 16pub(crate) struct Arch {
17 default_entry: Option<&'static str>,
18 flavor: Flavor,
19}
8 20
9#[derive(Debug, FromMeta)] 21pub static ARCH_AVR: Arch = Arch {
22 default_entry: Some("avr_device::entry"),
23 flavor: Flavor::Standard,
24};
25
26pub static ARCH_RISCV: Arch = Arch {
27 default_entry: Some("riscv_rt::entry"),
28 flavor: Flavor::Standard,
29};
30
31pub static ARCH_CORTEX_M: Arch = Arch {
32 default_entry: Some("cortex_m_rt::entry"),
33 flavor: Flavor::Standard,
34};
35
36pub static ARCH_SPIN: Arch = Arch {
37 default_entry: None,
38 flavor: Flavor::Standard,
39};
40
41pub static ARCH_STD: Arch = Arch {
42 default_entry: None,
43 flavor: Flavor::Standard,
44};
45
46pub static ARCH_WASM: Arch = Arch {
47 default_entry: Some("wasm_bindgen::prelude::wasm_bindgen(start)"),
48 flavor: Flavor::Wasm,
49};
50
51#[derive(Debug, FromMeta, Default)]
10struct Args { 52struct Args {
11 #[darling(default)] 53 #[darling(default)]
12 entry: Option<String>, 54 entry: Option<String>,
13} 55}
14 56
15pub fn avr() -> TokenStream { 57pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream {
16 quote! { 58 let mut errors = TokenStream::new();
17 #[avr_device::entry]
18 fn main() -> ! {
19 let mut executor = ::embassy_executor::Executor::new();
20 let executor = unsafe { __make_static(&mut executor) };
21 59
22 executor.run(|spawner| { 60 // If any of the steps for this macro fail, we still want to expand to an item that is as close
23 spawner.must_spawn(__embassy_main(spawner)); 61 // to the expected output as possible. This helps out IDEs such that completions and other
24 }) 62 // related features keep working.
25 } 63 let f: ItemFn = match syn::parse2(item.clone()) {
26 } 64 Ok(x) => x,
27} 65 Err(e) => return token_stream_with_error(item, e),
28
29pub fn riscv(args: &[NestedMeta]) -> TokenStream {
30 let maybe_entry = match Args::from_list(args) {
31 Ok(args) => args.entry,
32 Err(e) => return e.write_errors(),
33 }; 66 };
34 67
35 let entry = maybe_entry.unwrap_or("riscv_rt::entry".into()); 68 let args = match NestedMeta::parse_meta_list(args) {
36 let entry = match Expr::from_string(&entry) { 69 Ok(x) => x,
37 Ok(expr) => expr, 70 Err(e) => return token_stream_with_error(item, e),
38 Err(e) => return e.write_errors(),
39 }; 71 };
40 72
41 quote! { 73 let args = match Args::from_list(&args) {
42 #[#entry] 74 Ok(x) => x,
43 fn main() -> ! { 75 Err(e) => {
44 let mut executor = ::embassy_executor::Executor::new(); 76 errors.extend(e.write_errors());
45 let executor = unsafe { __make_static(&mut executor) }; 77 Args::default()
46 executor.run(|spawner| {
47 spawner.must_spawn(__embassy_main(spawner));
48 })
49 } 78 }
50 }
51}
52
53pub fn spin(args: &[NestedMeta]) -> TokenStream {
54 let maybe_entry = match Args::from_list(args) {
55 Ok(args) => args.entry,
56 Err(e) => return e.write_errors(),
57 };
58
59 let entry = match maybe_entry {
60 Some(str) => str,
61 None => return Error::missing_field("entry").write_errors(),
62 }; 79 };
63 let entry = match Expr::from_string(&entry) {
64 Ok(expr) => expr,
65 Err(e) => return e.write_errors(),
66 };
67
68 quote! {
69 #[#entry]
70 fn main() -> ! {
71 let mut executor = ::embassy_executor::Executor::new();
72 let executor = unsafe { __make_static(&mut executor) };
73 executor.run(|spawner| {
74 spawner.must_spawn(__embassy_main(spawner));
75 })
76 }
77 }
78}
79
80pub fn cortex_m() -> TokenStream {
81 quote! {
82 #[cortex_m_rt::entry]
83 fn main() -> ! {
84 let mut executor = ::embassy_executor::Executor::new();
85 let executor = unsafe { __make_static(&mut executor) };
86 executor.run(|spawner| {
87 spawner.must_spawn(__embassy_main(spawner));
88 })
89 }
90 }
91}
92
93pub fn wasm() -> TokenStream {
94 quote! {
95 #[wasm_bindgen::prelude::wasm_bindgen(start)]
96 pub fn main() -> Result<(), wasm_bindgen::JsValue> {
97 let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
98
99 executor.start(|spawner| {
100 spawner.must_spawn(__embassy_main(spawner));
101 });
102
103 Ok(())
104 }
105 }
106}
107
108pub fn std() -> TokenStream {
109 quote! {
110 fn main() -> ! {
111 let mut executor = ::embassy_executor::Executor::new();
112 let executor = unsafe { __make_static(&mut executor) };
113
114 executor.run(|spawner| {
115 spawner.must_spawn(__embassy_main(spawner));
116 })
117 }
118 }
119}
120
121pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
122 #[allow(unused_variables)]
123 let args = Args::from_list(args).map_err(|e| e.write_errors())?;
124 80
125 let fargs = f.sig.inputs.clone(); 81 let fargs = f.sig.inputs.clone();
126 82
127 let ctxt = Ctxt::new();
128
129 if f.sig.asyncness.is_none() { 83 if f.sig.asyncness.is_none() {
130 ctxt.error_spanned_by(&f.sig, "main function must be async"); 84 error(&mut errors, &f.sig, "main function must be async");
131 } 85 }
132 if !f.sig.generics.params.is_empty() { 86 if !f.sig.generics.params.is_empty() {
133 ctxt.error_spanned_by(&f.sig, "main function must not be generic"); 87 error(&mut errors, &f.sig, "main function must not be generic");
134 } 88 }
135 if !f.sig.generics.where_clause.is_none() { 89 if !f.sig.generics.where_clause.is_none() {
136 ctxt.error_spanned_by(&f.sig, "main function must not have `where` clauses"); 90 error(&mut errors, &f.sig, "main function must not have `where` clauses");
137 } 91 }
138 if !f.sig.abi.is_none() { 92 if !f.sig.abi.is_none() {
139 ctxt.error_spanned_by(&f.sig, "main function must not have an ABI qualifier"); 93 error(&mut errors, &f.sig, "main function must not have an ABI qualifier");
140 } 94 }
141 if !f.sig.variadic.is_none() { 95 if !f.sig.variadic.is_none() {
142 ctxt.error_spanned_by(&f.sig, "main function must not be variadic"); 96 error(&mut errors, &f.sig, "main function must not be variadic");
143 } 97 }
144 match &f.sig.output { 98 match &f.sig.output {
145 ReturnType::Default => {} 99 ReturnType::Default => {}
146 ReturnType::Type(_, ty) => match &**ty { 100 ReturnType::Type(_, ty) => match &**ty {
147 Type::Tuple(tuple) if tuple.elems.is_empty() => {} 101 Type::Tuple(tuple) if tuple.elems.is_empty() => {}
148 Type::Never(_) => {} 102 Type::Never(_) => {}
149 _ => ctxt.error_spanned_by( 103 _ => error(
104 &mut errors,
150 &f.sig, 105 &f.sig,
151 "main function must either not return a value, return `()` or return `!`", 106 "main function must either not return a value, return `()` or return `!`",
152 ), 107 ),
@@ -154,26 +109,69 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result<Tok
154 } 109 }
155 110
156 if fargs.len() != 1 { 111 if fargs.len() != 1 {
157 ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner."); 112 error(&mut errors, &f.sig, "main function must have 1 argument: the spawner.");
158 } 113 }
159 114
160 ctxt.check()?; 115 let entry = match args.entry.as_deref().or(arch.default_entry) {
116 None => TokenStream::new(),
117 Some(x) => match TokenStream::from_str(x) {
118 Ok(x) => quote!(#[#x]),
119 Err(e) => {
120 error(&mut errors, &f.sig, e);
121 TokenStream::new()
122 }
123 },
124 };
161 125
162 let f_body = f.block; 126 let f_body = f.body;
163 let out = &f.sig.output; 127 let out = &f.sig.output;
164 128
129 let (main_ret, mut main_body) = match arch.flavor {
130 Flavor::Standard => (
131 quote!(!),
132 quote! {
133 unsafe fn __make_static<T>(t: &mut T) -> &'static mut T {
134 ::core::mem::transmute(t)
135 }
136
137 let mut executor = ::embassy_executor::Executor::new();
138 let executor = unsafe { __make_static(&mut executor) };
139 executor.run(|spawner| {
140 spawner.must_spawn(__embassy_main(spawner));
141 })
142 },
143 ),
144 Flavor::Wasm => (
145 quote!(Result<(), wasm_bindgen::JsValue>),
146 quote! {
147 let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
148
149 executor.start(|spawner| {
150 spawner.must_spawn(__embassy_main(spawner));
151 });
152
153 Ok(())
154 },
155 ),
156 };
157
158 if !errors.is_empty() {
159 main_body = quote! {loop{}};
160 }
161
165 let result = quote! { 162 let result = quote! {
166 #[::embassy_executor::task()] 163 #[::embassy_executor::task()]
167 async fn __embassy_main(#fargs) #out { 164 async fn __embassy_main(#fargs) #out {
168 #f_body 165 #f_body
169 } 166 }
170 167
171 unsafe fn __make_static<T>(t: &mut T) -> &'static mut T { 168 #entry
172 ::core::mem::transmute(t) 169 fn main() -> #main_ret {
170 #main_body
173 } 171 }
174 172
175 #main 173 #errors
176 }; 174 };
177 175
178 Ok(result) 176 result
179} 177}