embassy_macros/lib.rs
1#![doc = include_str!("../README.md")]
2extern crate proc_macro;
3
4use darling::ast::NestedMeta;
5use proc_macro::TokenStream;
6
7mod macros;
8mod util;
9use macros::*;
10use syn::parse::{Parse, ParseBuffer};
11use syn::punctuated::Punctuated;
12use syn::Token;
13
14struct Args {
15 meta: Vec<NestedMeta>,
16}
17
18impl Parse for Args {
19 fn parse(input: &ParseBuffer) -> syn::Result<Self> {
20 let meta = Punctuated::<NestedMeta, Token![,]>::parse_terminated(input)?;
21 Ok(Args {
22 meta: meta.into_iter().collect(),
23 })
24 }
25}
26
27/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how
28/// many concurrent tasks can be spawned (default is 1) for the function.
29///
30///
31/// The following restrictions apply:
32///
33/// * The function must be declared `async`.
34/// * The function must not use generics.
35/// * The optional `pool_size` attribute must be 1 or greater.
36///
37///
38/// ## Examples
39///
40/// Declaring a task taking no arguments:
41///
42/// ``` rust
43/// #[embassy_executor::task]
44/// async fn mytask() {
45/// // Function body
46/// }
47/// ```
48///
49/// Declaring a task with a given pool size:
50///
51/// ``` rust
52/// #[embassy_executor::task(pool_size = 4)]
53/// async fn mytask() {
54/// // Function body
55/// }
56/// ```
57#[proc_macro_attribute]
58pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
59 let args = syn::parse_macro_input!(args as Args);
60 let f = syn::parse_macro_input!(item as syn::ItemFn);
61
62 task::run(&args.meta, f).unwrap_or_else(|x| x).into()
63}
64
65/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
66///
67/// The following restrictions apply:
68///
69/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
70/// * The function must be declared `async`.
71/// * The function must not use generics.
72/// * Only a single `main` task may be declared.
73///
74/// ## Examples
75/// Spawning a task:
76///
77/// ``` rust
78/// #[embassy_executor::main]
79/// async fn main(_s: embassy_executor::Spawner) {
80/// // Function body
81/// }
82/// ```
83#[proc_macro_attribute]
84pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
85 let args = syn::parse_macro_input!(args as Args);
86 let f = syn::parse_macro_input!(item as syn::ItemFn);
87 main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into()
88}
89
90/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
91///
92/// The following restrictions apply:
93///
94/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
95/// * The function must be declared `async`.
96/// * The function must not use generics.
97/// * Only a single `main` task may be declared.
98///
99/// A user-defined entry macro can be optionally provided via the `entry` argument to override the default of `riscv_rt::entry`.
100///
101/// ## Examples
102/// Spawning a task:
103///
104/// ``` rust
105/// #[embassy_executor::main]
106/// async fn main(_s: embassy_executor::Spawner) {
107/// // Function body
108/// }
109/// ```
110///
111/// Spawning a task using a custom entry macro:
112/// ``` rust
113/// #[embassy_executor::main(entry = "esp_riscv_rt::entry")]
114/// async fn main(_s: embassy_executor::Spawner) {
115/// // Function body
116/// }
117/// ```
118#[proc_macro_attribute]
119pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
120 let args = syn::parse_macro_input!(args as Args);
121 let f = syn::parse_macro_input!(item as syn::ItemFn);
122 main::run(&args.meta, f, main::riscv(&args.meta))
123 .unwrap_or_else(|x| x)
124 .into()
125}
126
127/// Creates a new `executor` instance and declares an application entry point for STD spawning the corresponding function body as an async task.
128///
129/// The following restrictions apply:
130///
131/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
132/// * The function must be declared `async`.
133/// * The function must not use generics.
134/// * Only a single `main` task may be declared.
135///
136/// ## Examples
137/// Spawning a task:
138///
139/// ``` rust
140/// #[embassy_executor::main]
141/// async fn main(_s: embassy_executor::Spawner) {
142/// // Function body
143/// }
144/// ```
145#[proc_macro_attribute]
146pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
147 let args = syn::parse_macro_input!(args as Args);
148 let f = syn::parse_macro_input!(item as syn::ItemFn);
149 main::run(&args.meta, f, main::std()).unwrap_or_else(|x| x).into()
150}
151
152/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
153///
154/// The following restrictions apply:
155///
156/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
157/// * The function must be declared `async`.
158/// * The function must not use generics.
159/// * Only a single `main` task may be declared.
160///
161/// ## Examples
162/// Spawning a task:
163///
164/// ``` rust
165/// #[embassy_executor::main]
166/// async fn main(_s: embassy_executor::Spawner) {
167/// // Function body
168/// }
169/// ```
170#[proc_macro_attribute]
171pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
172 let args = syn::parse_macro_input!(args as Args);
173 let f = syn::parse_macro_input!(item as syn::ItemFn);
174 main::run(&args.meta, f, main::wasm()).unwrap_or_else(|x| x).into()
175}