Merge pull request #1583 from bugadani/const
Allow path expressions as `task(pool_size)`
This commit is contained in:
commit
d8c70c5c3e
5 changed files with 51 additions and 28 deletions
|
@ -12,9 +12,9 @@ categories = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syn = { version = "1.0.76", features = ["full", "extra-traits"] }
|
syn = { version = "2.0.15", features = ["full", "extra-traits"] }
|
||||||
quote = "1.0.9"
|
quote = "1.0.9"
|
||||||
darling = "0.13.0"
|
darling = "0.20.1"
|
||||||
proc-macro2 = "1.0.29"
|
proc-macro2 = "1.0.29"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
|
@ -1,11 +1,28 @@
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use darling::ast::NestedMeta;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
mod macros;
|
mod macros;
|
||||||
mod util;
|
mod util;
|
||||||
use macros::*;
|
use macros::*;
|
||||||
|
use syn::parse::{Parse, ParseBuffer};
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::Token;
|
||||||
|
|
||||||
|
struct Args {
|
||||||
|
meta: Vec<NestedMeta>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Args {
|
||||||
|
fn parse(input: &ParseBuffer) -> syn::Result<Self> {
|
||||||
|
let meta = Punctuated::<NestedMeta, Token![,]>::parse_terminated(input)?;
|
||||||
|
Ok(Args {
|
||||||
|
meta: meta.into_iter().collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how
|
/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how
|
||||||
/// many concurrent tasks can be spawned (default is 1) for the function.
|
/// many concurrent tasks can be spawned (default is 1) for the function.
|
||||||
|
@ -39,10 +56,10 @@ use macros::*;
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
let args = syn::parse_macro_input!(args as Args);
|
||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
|
|
||||||
task::run(args, f).unwrap_or_else(|x| x).into()
|
task::run(&args.meta, f).unwrap_or_else(|x| x).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
|
/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
|
||||||
|
@ -65,9 +82,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
let args = syn::parse_macro_input!(args as Args);
|
||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into()
|
main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
|
/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
|
||||||
|
@ -100,9 +117,9 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
let args = syn::parse_macro_input!(args as Args);
|
||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
main::run(args.clone(), f, main::riscv(args))
|
main::run(&args.meta, f, main::riscv(&args.meta))
|
||||||
.unwrap_or_else(|x| x)
|
.unwrap_or_else(|x| x)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
@ -127,9 +144,9 @@ pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
let args = syn::parse_macro_input!(args as Args);
|
||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
main::run(args, f, main::std()).unwrap_or_else(|x| x).into()
|
main::run(&args.meta, f, main::std()).unwrap_or_else(|x| x).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
|
/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
|
||||||
|
@ -152,7 +169,7 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
let args = syn::parse_macro_input!(args as Args);
|
||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
|
main::run(&args.meta, f, main::wasm()).unwrap_or_else(|x| x).into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use darling::export::NestedMeta;
|
||||||
use darling::FromMeta;
|
use darling::FromMeta;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -11,8 +12,8 @@ struct Args {
|
||||||
entry: Option<String>,
|
entry: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn riscv(args: syn::AttributeArgs) -> TokenStream {
|
pub fn riscv(args: &[NestedMeta]) -> TokenStream {
|
||||||
let maybe_entry = match Args::from_list(&args) {
|
let maybe_entry = match Args::from_list(args) {
|
||||||
Ok(args) => args.entry,
|
Ok(args) => args.entry,
|
||||||
Err(e) => return e.write_errors(),
|
Err(e) => return e.write_errors(),
|
||||||
};
|
};
|
||||||
|
@ -77,9 +78,9 @@ pub fn std() -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
|
pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
|
let args = Args::from_list(args).map_err(|e| e.write_errors())?;
|
||||||
|
|
||||||
let fargs = f.sig.inputs.clone();
|
let fargs = f.sig.inputs.clone();
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
|
use darling::export::NestedMeta;
|
||||||
use darling::FromMeta;
|
use darling::FromMeta;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{parse_quote, ItemFn, ReturnType, Type};
|
use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type};
|
||||||
|
|
||||||
use crate::util::ctxt::Ctxt;
|
use crate::util::ctxt::Ctxt;
|
||||||
|
|
||||||
#[derive(Debug, FromMeta)]
|
#[derive(Debug, FromMeta)]
|
||||||
struct Args {
|
struct Args {
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pool_size: Option<usize>,
|
pool_size: Option<syn::Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
|
pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
|
||||||
let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
|
let args = Args::from_list(args).map_err(|e| e.write_errors())?;
|
||||||
|
|
||||||
let pool_size: usize = args.pool_size.unwrap_or(1);
|
let pool_size = args.pool_size.unwrap_or(Expr::Lit(ExprLit {
|
||||||
|
attrs: vec![],
|
||||||
|
lit: Lit::Int(LitInt::new("1", Span::call_site())),
|
||||||
|
}));
|
||||||
|
|
||||||
let ctxt = Ctxt::new();
|
let ctxt = Ctxt::new();
|
||||||
|
|
||||||
|
@ -45,10 +49,6 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if pool_size < 1 {
|
|
||||||
ctxt.error_spanned_by(&f.sig, "pool_size must be 1 or greater");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut arg_names = Vec::new();
|
let mut arg_names = Vec::new();
|
||||||
let mut fargs = f.sig.inputs.clone();
|
let mut fargs = f.sig.inputs.clone();
|
||||||
|
|
||||||
|
@ -82,7 +82,8 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
|
||||||
let mut task_outer: ItemFn = parse_quote! {
|
let mut task_outer: ItemFn = parse_quote! {
|
||||||
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
|
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
|
||||||
type Fut = impl ::core::future::Future + 'static;
|
type Fut = impl ::core::future::Future + 'static;
|
||||||
static POOL: ::embassy_executor::raw::TaskPool<Fut, #pool_size> = ::embassy_executor::raw::TaskPool::new();
|
const POOL_SIZE: usize = #pool_size;
|
||||||
|
static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new();
|
||||||
unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
|
unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,11 @@ use embassy_executor::Spawner;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::task(pool_size = 2)]
|
mod config {
|
||||||
|
pub const MY_TASK_POOL_SIZE: usize = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task(pool_size = config::MY_TASK_POOL_SIZE)]
|
||||||
async fn my_task(spawner: Spawner, n: u32) {
|
async fn my_task(spawner: Spawner, n: u32) {
|
||||||
Timer::after(Duration::from_secs(1)).await;
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
info!("Spawning self! {}", n);
|
info!("Spawning self! {}", n);
|
||||||
|
|
Loading…
Reference in a new issue