diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-04-26 18:36:38 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-26 18:40:45 +0200 |
| commit | 96d917992ca591def3d7be87bc9f03486549b2a0 (patch) | |
| tree | b810ff7103bf1af242b55e568ff75fb54b88958c /embassy-macros | |
| parent | a39d796c3de9c96ea4df6b9da525cb0d5ef60fc0 (diff) | |
macros: simplify task macro using "TAIT laundering".
Diffstat (limited to 'embassy-macros')
| -rw-r--r-- | embassy-macros/src/macros/task.rs | 31 |
1 files changed, 14 insertions, 17 deletions
diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs index c37ad212c..396ce18f2 100644 --- a/embassy-macros/src/macros/task.rs +++ b/embassy-macros/src/macros/task.rs | |||
| @@ -33,12 +33,10 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke | |||
| 33 | ctxt.error_spanned_by(&f.sig, "pool_size must be 1 or greater"); | 33 | ctxt.error_spanned_by(&f.sig, "pool_size must be 1 or greater"); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | let mut arg_types = Vec::new(); | ||
| 37 | let mut arg_names = Vec::new(); | 36 | let mut arg_names = Vec::new(); |
| 38 | let mut arg_indexes = Vec::new(); | ||
| 39 | let mut fargs = f.sig.inputs.clone(); | 37 | let mut fargs = f.sig.inputs.clone(); |
| 40 | 38 | ||
| 41 | for (i, arg) in fargs.iter_mut().enumerate() { | 39 | for arg in fargs.iter_mut() { |
| 42 | match arg { | 40 | match arg { |
| 43 | syn::FnArg::Receiver(_) => { | 41 | syn::FnArg::Receiver(_) => { |
| 44 | ctxt.error_spanned_by(arg, "task functions must not have receiver arguments"); | 42 | ctxt.error_spanned_by(arg, "task functions must not have receiver arguments"); |
| @@ -46,8 +44,6 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke | |||
| 46 | syn::FnArg::Typed(t) => match t.pat.as_mut() { | 44 | syn::FnArg::Typed(t) => match t.pat.as_mut() { |
| 47 | syn::Pat::Ident(id) => { | 45 | syn::Pat::Ident(id) => { |
| 48 | arg_names.push(id.ident.clone()); | 46 | arg_names.push(id.ident.clone()); |
| 49 | arg_types.push(t.ty.clone()); | ||
| 50 | arg_indexes.push(syn::Index::from(i)); | ||
| 51 | id.mutability = None; | 47 | id.mutability = None; |
| 52 | } | 48 | } |
| 53 | _ => { | 49 | _ => { |
| @@ -64,8 +60,6 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke | |||
| 64 | 60 | ||
| 65 | let task_ident = f.sig.ident.clone(); | 61 | let task_ident = f.sig.ident.clone(); |
| 66 | let task_inner_ident = format_ident!("__{}_task", task_ident); | 62 | let task_inner_ident = format_ident!("__{}_task", task_ident); |
| 67 | let mod_ident = format_ident!("__{}_mod", task_ident); | ||
| 68 | let args_ident = format_ident!("__{}_args", task_ident); | ||
| 69 | 63 | ||
| 70 | let mut task_inner = f; | 64 | let mut task_inner = f; |
| 71 | let visibility = task_inner.vis.clone(); | 65 | let visibility = task_inner.vis.clone(); |
| @@ -73,29 +67,32 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke | |||
| 73 | task_inner.sig.ident = task_inner_ident.clone(); | 67 | task_inner.sig.ident = task_inner_ident.clone(); |
| 74 | 68 | ||
| 75 | let result = quote! { | 69 | let result = quote! { |
| 70 | // This is the user's task function, renamed. | ||
| 71 | // We put it outside the #task_ident fn below, because otherwise | ||
| 72 | // the items defined there (such as POOL) would be in scope | ||
| 73 | // in the user's code. | ||
| 76 | #task_inner | 74 | #task_inner |
| 77 | 75 | ||
| 78 | #[allow(non_camel_case_types)] | 76 | #visibility fn #task_ident(#fargs) -> #embassy_path::executor::SpawnToken<impl ::core::future::Future + 'static> { |
| 79 | type #args_ident = (#(#arg_types,)*); | 77 | use ::core::future::Future; |
| 80 | |||
| 81 | mod #mod_ident { | ||
| 82 | use #embassy_path::executor::SpawnToken; | 78 | use #embassy_path::executor::SpawnToken; |
| 83 | use #embassy_path::executor::raw::TaskStorage; | 79 | use #embassy_path::executor::raw::TaskStorage; |
| 84 | 80 | ||
| 85 | type Fut = impl ::core::future::Future + 'static; | 81 | type Fut = impl Future + 'static; |
| 86 | 82 | ||
| 87 | #[allow(clippy::declare_interior_mutable_const)] | 83 | #[allow(clippy::declare_interior_mutable_const)] |
| 88 | const NEW_TS: TaskStorage<Fut> = TaskStorage::new(); | 84 | const NEW_TS: TaskStorage<Fut> = TaskStorage::new(); |
| 89 | 85 | ||
| 90 | static POOL: [TaskStorage<Fut>; #pool_size] = [NEW_TS; #pool_size]; | 86 | static POOL: [TaskStorage<Fut>; #pool_size] = [NEW_TS; #pool_size]; |
| 91 | 87 | ||
| 92 | pub(super) fn task(args: super::#args_ident) -> SpawnToken<Fut> { | 88 | // Opaque type laundering, to obscure its origin! |
| 93 | unsafe { TaskStorage::spawn_pool(&POOL, move || super::#task_inner_ident(#(args.#arg_indexes),*)) } | 89 | // Workaround for "opaque type's hidden type cannot be another opaque type from the same scope" |
| 90 | // https://github.com/rust-lang/rust/issues/96406 | ||
| 91 | fn launder_tait(token: SpawnToken<impl Future+'static>) -> SpawnToken<impl Future+'static> { | ||
| 92 | token | ||
| 94 | } | 93 | } |
| 95 | } | ||
| 96 | 94 | ||
| 97 | #visibility fn #task_ident(#fargs) -> #embassy_path::executor::SpawnToken<impl ::core::future::Future + 'static> { | 95 | launder_tait(unsafe { TaskStorage::spawn_pool(&POOL, move || #task_inner_ident(#(#arg_names,)*)) }) |
| 98 | #mod_ident::task((#(#arg_names,)*)) | ||
| 99 | } | 96 | } |
| 100 | }; | 97 | }; |
| 101 | 98 | ||
