aboutsummaryrefslogtreecommitdiff
path: root/embassy-macros
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-04-26 18:36:38 +0200
committerDario Nieuwenhuis <[email protected]>2022-04-26 18:40:45 +0200
commit96d917992ca591def3d7be87bc9f03486549b2a0 (patch)
treeb810ff7103bf1af242b55e568ff75fb54b88958c /embassy-macros
parenta39d796c3de9c96ea4df6b9da525cb0d5ef60fc0 (diff)
macros: simplify task macro using "TAIT laundering".
Diffstat (limited to 'embassy-macros')
-rw-r--r--embassy-macros/src/macros/task.rs31
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