aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor-macros/src/macros/task.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-12-07 00:43:18 +0100
committerDario Nieuwenhuis <[email protected]>2023-12-07 00:48:30 +0100
commitac2aec4e7a8e8a4c17c611810d382892398c9eb7 (patch)
tree6ac62c9f6d41e53d0f7f6d9737b1c0c206e531b3 /embassy-executor-macros/src/macros/task.rs
parentad2d9040d9f36d2523a22752e98f24c661643cb7 (diff)
executor: rename macro crate to embassy-executor-macros, bump it.
Diffstat (limited to 'embassy-executor-macros/src/macros/task.rs')
-rw-r--r--embassy-executor-macros/src/macros/task.rs114
1 files changed, 114 insertions, 0 deletions
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs
new file mode 100644
index 000000000..5161e1020
--- /dev/null
+++ b/embassy-executor-macros/src/macros/task.rs
@@ -0,0 +1,114 @@
1use darling::export::NestedMeta;
2use darling::FromMeta;
3use proc_macro2::{Span, TokenStream};
4use quote::{format_ident, quote};
5use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type};
6
7use crate::util::ctxt::Ctxt;
8
9#[derive(Debug, FromMeta)]
10struct Args {
11 #[darling(default)]
12 pool_size: Option<syn::Expr>,
13}
14
15pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
16 let args = Args::from_list(args).map_err(|e| e.write_errors())?;
17
18 let pool_size = args.pool_size.unwrap_or(Expr::Lit(ExprLit {
19 attrs: vec![],
20 lit: Lit::Int(LitInt::new("1", Span::call_site())),
21 }));
22
23 let ctxt = Ctxt::new();
24
25 if f.sig.asyncness.is_none() {
26 ctxt.error_spanned_by(&f.sig, "task functions must be async");
27 }
28 if !f.sig.generics.params.is_empty() {
29 ctxt.error_spanned_by(&f.sig, "task functions must not be generic");
30 }
31 if !f.sig.generics.where_clause.is_none() {
32 ctxt.error_spanned_by(&f.sig, "task functions must not have `where` clauses");
33 }
34 if !f.sig.abi.is_none() {
35 ctxt.error_spanned_by(&f.sig, "task functions must not have an ABI qualifier");
36 }
37 if !f.sig.variadic.is_none() {
38 ctxt.error_spanned_by(&f.sig, "task functions must not be variadic");
39 }
40 match &f.sig.output {
41 ReturnType::Default => {}
42 ReturnType::Type(_, ty) => match &**ty {
43 Type::Tuple(tuple) if tuple.elems.is_empty() => {}
44 Type::Never(_) => {}
45 _ => ctxt.error_spanned_by(
46 &f.sig,
47 "task functions must either not return a value, return `()` or return `!`",
48 ),
49 },
50 }
51
52 let mut arg_names = Vec::new();
53 let mut fargs = f.sig.inputs.clone();
54
55 for arg in fargs.iter_mut() {
56 match arg {
57 syn::FnArg::Receiver(_) => {
58 ctxt.error_spanned_by(arg, "task functions must not have receiver arguments");
59 }
60 syn::FnArg::Typed(t) => match t.pat.as_mut() {
61 syn::Pat::Ident(id) => {
62 arg_names.push(id.ident.clone());
63 id.mutability = None;
64 }
65 _ => {
66 ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported");
67 }
68 },
69 }
70 }
71
72 ctxt.check()?;
73
74 let task_ident = f.sig.ident.clone();
75 let task_inner_ident = format_ident!("__{}_task", task_ident);
76
77 let mut task_inner = f;
78 let visibility = task_inner.vis.clone();
79 task_inner.vis = syn::Visibility::Inherited;
80 task_inner.sig.ident = task_inner_ident.clone();
81
82 #[cfg(feature = "nightly")]
83 let mut task_outer: ItemFn = parse_quote! {
84 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
85 type Fut = impl ::core::future::Future + 'static;
86 const POOL_SIZE: usize = #pool_size;
87 static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new();
88 unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
89 }
90 };
91 #[cfg(not(feature = "nightly"))]
92 let mut task_outer: ItemFn = parse_quote! {
93 #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
94 const POOL_SIZE: usize = #pool_size;
95 static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new();
96 unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
97 }
98 };
99
100 task_outer.attrs.append(&mut task_inner.attrs.clone());
101
102 let result = quote! {
103 // This is the user's task function, renamed.
104 // We put it outside the #task_ident fn below, because otherwise
105 // the items defined there (such as POOL) would be in scope
106 // in the user's code.
107 #[doc(hidden)]
108 #task_inner
109
110 #task_outer
111 };
112
113 Ok(result)
114}