diff options
Diffstat (limited to 'embassy-executor-macros/src/macros')
| -rw-r--r-- | embassy-executor-macros/src/macros/main.rs | 22 | ||||
| -rw-r--r-- | embassy-executor-macros/src/macros/task.rs | 128 |
2 files changed, 116 insertions, 34 deletions
diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 95722b19b..dc470e51c 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs | |||
| @@ -37,6 +37,12 @@ pub static ARCH_CORTEX_M: Arch = Arch { | |||
| 37 | executor_required: false, | 37 | executor_required: false, |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | pub static ARCH_CORTEX_AR: Arch = Arch { | ||
| 41 | default_entry: None, | ||
| 42 | flavor: Flavor::Standard, | ||
| 43 | executor_required: false, | ||
| 44 | }; | ||
| 45 | |||
| 40 | pub static ARCH_SPIN: Arch = Arch { | 46 | pub static ARCH_SPIN: Arch = Arch { |
| 41 | default_entry: None, | 47 | default_entry: None, |
| 42 | flavor: Flavor::Standard, | 48 | flavor: Flavor::Standard, |
| @@ -164,6 +170,14 @@ For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Exe | |||
| 164 | let f_body = f.body; | 170 | let f_body = f.body; |
| 165 | let out = &f.sig.output; | 171 | let out = &f.sig.output; |
| 166 | 172 | ||
| 173 | let name_main_task = if cfg!(feature = "metadata-name") { | ||
| 174 | quote!( | ||
| 175 | main_task.metadata().set_name("main\0"); | ||
| 176 | ) | ||
| 177 | } else { | ||
| 178 | quote!() | ||
| 179 | }; | ||
| 180 | |||
| 167 | let (main_ret, mut main_body) = match arch.flavor { | 181 | let (main_ret, mut main_body) = match arch.flavor { |
| 168 | Flavor::Standard => ( | 182 | Flavor::Standard => ( |
| 169 | quote!(!), | 183 | quote!(!), |
| @@ -175,7 +189,9 @@ For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Exe | |||
| 175 | let mut executor = #executor::new(); | 189 | let mut executor = #executor::new(); |
| 176 | let executor = unsafe { __make_static(&mut executor) }; | 190 | let executor = unsafe { __make_static(&mut executor) }; |
| 177 | executor.run(|spawner| { | 191 | executor.run(|spawner| { |
| 178 | spawner.must_spawn(__embassy_main(spawner)); | 192 | let main_task = __embassy_main(spawner).unwrap(); |
| 193 | #name_main_task | ||
| 194 | spawner.spawn(main_task); | ||
| 179 | }) | 195 | }) |
| 180 | }, | 196 | }, |
| 181 | ), | 197 | ), |
| @@ -185,7 +201,9 @@ For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Exe | |||
| 185 | let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(#executor::new())); | 201 | let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(#executor::new())); |
| 186 | 202 | ||
| 187 | executor.start(|spawner| { | 203 | executor.start(|spawner| { |
| 188 | spawner.must_spawn(__embassy_main(spawner)); | 204 | let main_task = __embassy_main(spawner).unwrap(); |
| 205 | #name_main_task | ||
| 206 | spawner.spawn(main_task); | ||
| 189 | }); | 207 | }); |
| 190 | 208 | ||
| 191 | Ok(()) | 209 | Ok(()) |
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 91d6beee8..755948882 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs | |||
| @@ -5,7 +5,7 @@ use darling::FromMeta; | |||
| 5 | use proc_macro2::{Span, TokenStream}; | 5 | use proc_macro2::{Span, TokenStream}; |
| 6 | use quote::{format_ident, quote}; | 6 | use quote::{format_ident, quote}; |
| 7 | use syn::visit::{self, Visit}; | 7 | use syn::visit::{self, Visit}; |
| 8 | use syn::{Expr, ExprLit, Lit, LitInt, ReturnType, Type}; | 8 | use syn::{Expr, ExprLit, Lit, LitInt, ReturnType, Type, Visibility}; |
| 9 | 9 | ||
| 10 | use crate::util::*; | 10 | use crate::util::*; |
| 11 | 11 | ||
| @@ -51,7 +51,11 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 51 | .embassy_executor | 51 | .embassy_executor |
| 52 | .unwrap_or(Expr::Verbatim(TokenStream::from_str("::embassy_executor").unwrap())); | 52 | .unwrap_or(Expr::Verbatim(TokenStream::from_str("::embassy_executor").unwrap())); |
| 53 | 53 | ||
| 54 | if f.sig.asyncness.is_none() { | 54 | let returns_impl_trait = match &f.sig.output { |
| 55 | ReturnType::Type(_, ty) => matches!(**ty, Type::ImplTrait(_)), | ||
| 56 | _ => false, | ||
| 57 | }; | ||
| 58 | if f.sig.asyncness.is_none() && !returns_impl_trait { | ||
| 55 | error(&mut errors, &f.sig, "task functions must be async"); | 59 | error(&mut errors, &f.sig, "task functions must be async"); |
| 56 | } | 60 | } |
| 57 | if !f.sig.generics.params.is_empty() { | 61 | if !f.sig.generics.params.is_empty() { |
| @@ -66,17 +70,19 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 66 | if !f.sig.variadic.is_none() { | 70 | if !f.sig.variadic.is_none() { |
| 67 | error(&mut errors, &f.sig, "task functions must not be variadic"); | 71 | error(&mut errors, &f.sig, "task functions must not be variadic"); |
| 68 | } | 72 | } |
| 69 | match &f.sig.output { | 73 | if f.sig.asyncness.is_some() { |
| 70 | ReturnType::Default => {} | 74 | match &f.sig.output { |
| 71 | ReturnType::Type(_, ty) => match &**ty { | 75 | ReturnType::Default => {} |
| 72 | Type::Tuple(tuple) if tuple.elems.is_empty() => {} | 76 | ReturnType::Type(_, ty) => match &**ty { |
| 73 | Type::Never(_) => {} | 77 | Type::Tuple(tuple) if tuple.elems.is_empty() => {} |
| 74 | _ => error( | 78 | Type::Never(_) => {} |
| 75 | &mut errors, | 79 | _ => error( |
| 76 | &f.sig, | 80 | &mut errors, |
| 77 | "task functions must either not return a value, return `()` or return `!`", | 81 | &f.sig, |
| 78 | ), | 82 | "task functions must either not return a value, return `()` or return `!`", |
| 79 | }, | 83 | ), |
| 84 | }, | ||
| 85 | } | ||
| 80 | } | 86 | } |
| 81 | 87 | ||
| 82 | let mut args = Vec::new(); | 88 | let mut args = Vec::new(); |
| @@ -106,13 +112,11 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 106 | } | 112 | } |
| 107 | } | 113 | } |
| 108 | 114 | ||
| 109 | let task_ident = f.sig.ident.clone(); | 115 | // Copy the generics + where clause to avoid more spurious errors. |
| 110 | let task_inner_ident = format_ident!("__{}_task", task_ident); | 116 | let generics = &f.sig.generics; |
| 111 | 117 | let where_clause = &f.sig.generics.where_clause; | |
| 112 | let mut task_inner = f.clone(); | 118 | let unsafety = &f.sig.unsafety; |
| 113 | let visibility = task_inner.vis.clone(); | 119 | let visibility = &f.vis; |
| 114 | task_inner.vis = syn::Visibility::Inherited; | ||
| 115 | task_inner.sig.ident = task_inner_ident.clone(); | ||
| 116 | 120 | ||
| 117 | // assemble the original input arguments, | 121 | // assemble the original input arguments, |
| 118 | // including any attributes that may have | 122 | // including any attributes that may have |
| @@ -125,15 +129,79 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 125 | )); | 129 | )); |
| 126 | } | 130 | } |
| 127 | 131 | ||
| 132 | let task_ident = f.sig.ident.clone(); | ||
| 133 | let task_inner_ident = format_ident!("__{}_task", task_ident); | ||
| 134 | |||
| 135 | let task_inner_future_output = match &f.sig.output { | ||
| 136 | ReturnType::Default => quote! {-> impl ::core::future::Future<Output = ()>}, | ||
| 137 | // Special case the never type since we can't stuff it into a `impl Future<Output = !>` | ||
| 138 | ReturnType::Type(arrow, maybe_never) | ||
| 139 | if f.sig.asyncness.is_some() && matches!(**maybe_never, Type::Never(_)) => | ||
| 140 | { | ||
| 141 | quote! { | ||
| 142 | #arrow impl ::core::future::Future<Output=#embassy_executor::_export::Never> | ||
| 143 | } | ||
| 144 | } | ||
| 145 | ReturnType::Type(arrow, maybe_never) if matches!(**maybe_never, Type::Never(_)) => quote! { | ||
| 146 | #arrow #maybe_never | ||
| 147 | }, | ||
| 148 | // Grab the arrow span, why not | ||
| 149 | ReturnType::Type(arrow, typ) if f.sig.asyncness.is_some() => quote! { | ||
| 150 | #arrow impl ::core::future::Future<Output = #typ> | ||
| 151 | }, | ||
| 152 | // We assume that if `f` isn't async, it must return `-> impl Future<...>` | ||
| 153 | // This is checked using traits later | ||
| 154 | ReturnType::Type(arrow, typ) => quote! { | ||
| 155 | #arrow #typ | ||
| 156 | }, | ||
| 157 | }; | ||
| 158 | |||
| 159 | // We have to rename the function since it might be recursive; | ||
| 160 | let mut task_inner_function = f.clone(); | ||
| 161 | let task_inner_function_ident = format_ident!("__{}_task_inner_function", task_ident); | ||
| 162 | task_inner_function.sig.ident = task_inner_function_ident.clone(); | ||
| 163 | task_inner_function.vis = Visibility::Inherited; | ||
| 164 | |||
| 165 | let task_inner_body = if errors.is_empty() { | ||
| 166 | quote! { | ||
| 167 | #task_inner_function | ||
| 168 | |||
| 169 | // SAFETY: All the preconditions to `#task_ident` apply to | ||
| 170 | // all contexts `#task_inner_ident` is called in | ||
| 171 | #unsafety { | ||
| 172 | #task_inner_function_ident(#(#full_args,)*) | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } else { | ||
| 176 | quote! { | ||
| 177 | async {::core::todo!()} | ||
| 178 | } | ||
| 179 | }; | ||
| 180 | |||
| 181 | let task_inner = quote! { | ||
| 182 | #visibility fn #task_inner_ident #generics (#fargs) | ||
| 183 | #task_inner_future_output | ||
| 184 | #where_clause | ||
| 185 | { | ||
| 186 | #task_inner_body | ||
| 187 | } | ||
| 188 | }; | ||
| 189 | |||
| 190 | let spawn = if returns_impl_trait { | ||
| 191 | quote!(spawn) | ||
| 192 | } else { | ||
| 193 | quote!(_spawn_async_fn) | ||
| 194 | }; | ||
| 195 | |||
| 128 | #[cfg(feature = "nightly")] | 196 | #[cfg(feature = "nightly")] |
| 129 | let mut task_outer_body = quote! { | 197 | let mut task_outer_body = quote! { |
| 130 | trait _EmbassyInternalTaskTrait { | 198 | trait _EmbassyInternalTaskTrait { |
| 131 | type Fut: ::core::future::Future + 'static; | 199 | type Fut: ::core::future::Future<Output: #embassy_executor::_export::TaskReturnValue> + 'static; |
| 132 | fn construct(#fargs) -> Self::Fut; | 200 | fn construct(#fargs) -> Self::Fut; |
| 133 | } | 201 | } |
| 134 | 202 | ||
| 135 | impl _EmbassyInternalTaskTrait for () { | 203 | impl _EmbassyInternalTaskTrait for () { |
| 136 | type Fut = impl core::future::Future + 'static; | 204 | type Fut = impl core::future::Future<Output: #embassy_executor::_export::TaskReturnValue> + 'static; |
| 137 | fn construct(#fargs) -> Self::Fut { | 205 | fn construct(#fargs) -> Self::Fut { |
| 138 | #task_inner_ident(#(#full_args,)*) | 206 | #task_inner_ident(#(#full_args,)*) |
| 139 | } | 207 | } |
| @@ -141,7 +209,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 141 | 209 | ||
| 142 | const POOL_SIZE: usize = #pool_size; | 210 | const POOL_SIZE: usize = #pool_size; |
| 143 | static POOL: #embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = #embassy_executor::raw::TaskPool::new(); | 211 | static POOL: #embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = #embassy_executor::raw::TaskPool::new(); |
| 144 | unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } | 212 | unsafe { POOL.#spawn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } |
| 145 | }; | 213 | }; |
| 146 | #[cfg(not(feature = "nightly"))] | 214 | #[cfg(not(feature = "nightly"))] |
| 147 | let mut task_outer_body = quote! { | 215 | let mut task_outer_body = quote! { |
| @@ -158,23 +226,19 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 158 | {#embassy_executor::_export::task_pool_size::<_, _, _, POOL_SIZE>(#task_inner_ident)}, | 226 | {#embassy_executor::_export::task_pool_size::<_, _, _, POOL_SIZE>(#task_inner_ident)}, |
| 159 | {#embassy_executor::_export::task_pool_align::<_, _, _, POOL_SIZE>(#task_inner_ident)}, | 227 | {#embassy_executor::_export::task_pool_align::<_, _, _, POOL_SIZE>(#task_inner_ident)}, |
| 160 | > = unsafe { ::core::mem::transmute(#embassy_executor::_export::task_pool_new::<_, _, _, POOL_SIZE>(#task_inner_ident)) }; | 228 | > = unsafe { ::core::mem::transmute(#embassy_executor::_export::task_pool_new::<_, _, _, POOL_SIZE>(#task_inner_ident)) }; |
| 161 | unsafe { __task_pool_get(#task_inner_ident)._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } | 229 | unsafe { __task_pool_get(#task_inner_ident).#spawn(move || #task_inner_ident(#(#full_args,)*)) } |
| 162 | }; | 230 | }; |
| 163 | 231 | ||
| 164 | let task_outer_attrs = task_inner.attrs.clone(); | 232 | let task_outer_attrs = &f.attrs; |
| 165 | 233 | ||
| 166 | if !errors.is_empty() { | 234 | if !errors.is_empty() { |
| 167 | task_outer_body = quote! { | 235 | task_outer_body = quote! { |
| 168 | #![allow(unused_variables, unreachable_code)] | 236 | #![allow(unused_variables, unreachable_code)] |
| 169 | let _x: #embassy_executor::SpawnToken<()> = ::core::todo!(); | 237 | let _x: ::core::result::Result<#embassy_executor::SpawnToken<()>, #embassy_executor::SpawnError> = ::core::todo!(); |
| 170 | _x | 238 | _x |
| 171 | }; | 239 | }; |
| 172 | } | 240 | } |
| 173 | 241 | ||
| 174 | // Copy the generics + where clause to avoid more spurious errors. | ||
| 175 | let generics = &f.sig.generics; | ||
| 176 | let where_clause = &f.sig.generics.where_clause; | ||
| 177 | |||
| 178 | let result = quote! { | 242 | let result = quote! { |
| 179 | // This is the user's task function, renamed. | 243 | // This is the user's task function, renamed. |
| 180 | // We put it outside the #task_ident fn below, because otherwise | 244 | // We put it outside the #task_ident fn below, because otherwise |
| @@ -184,7 +248,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 184 | #task_inner | 248 | #task_inner |
| 185 | 249 | ||
| 186 | #(#task_outer_attrs)* | 250 | #(#task_outer_attrs)* |
| 187 | #visibility fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken<impl Sized> #where_clause{ | 251 | #visibility #unsafety fn #task_ident #generics (#fargs) -> ::core::result::Result<#embassy_executor::SpawnToken<impl Sized>, #embassy_executor::SpawnError> #where_clause{ |
| 188 | #task_outer_body | 252 | #task_outer_body |
| 189 | } | 253 | } |
| 190 | 254 | ||
| @@ -201,7 +265,7 @@ fn check_arg_ty(errors: &mut TokenStream, ty: &Type) { | |||
| 201 | 265 | ||
| 202 | impl<'a, 'ast> Visit<'ast> for Visitor<'a> { | 266 | impl<'a, 'ast> Visit<'ast> for Visitor<'a> { |
| 203 | fn visit_type_reference(&mut self, i: &'ast syn::TypeReference) { | 267 | fn visit_type_reference(&mut self, i: &'ast syn::TypeReference) { |
| 204 | // only check for elided lifetime here. If not elided, it's checked by `visit_lifetime`. | 268 | // Only check for elided lifetime here. If not elided, it's checked by `visit_lifetime`. |
| 205 | if i.lifetime.is_none() { | 269 | if i.lifetime.is_none() { |
| 206 | error( | 270 | error( |
| 207 | self.errors, | 271 | self.errors, |
