executor: rename macro crate to embassy-executor-macros, bump it.
This commit is contained in:
138
embassy-executor-macros/src/macros/main.rs
Normal file
138
embassy-executor-macros/src/macros/main.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use darling::export::NestedMeta;
|
||||
use darling::FromMeta;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Expr, ReturnType, Type};
|
||||
|
||||
use crate::util::ctxt::Ctxt;
|
||||
|
||||
#[derive(Debug, FromMeta)]
|
||||
struct Args {
|
||||
#[darling(default)]
|
||||
entry: Option<String>,
|
||||
}
|
||||
|
||||
pub fn riscv(args: &[NestedMeta]) -> TokenStream {
|
||||
let maybe_entry = match Args::from_list(args) {
|
||||
Ok(args) => args.entry,
|
||||
Err(e) => return e.write_errors(),
|
||||
};
|
||||
|
||||
let entry = maybe_entry.unwrap_or("riscv_rt::entry".into());
|
||||
let entry = match Expr::from_string(&entry) {
|
||||
Ok(expr) => expr,
|
||||
Err(e) => return e.write_errors(),
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[#entry]
|
||||
fn main() -> ! {
|
||||
let mut executor = ::embassy_executor::Executor::new();
|
||||
let executor = unsafe { __make_static(&mut executor) };
|
||||
executor.run(|spawner| {
|
||||
spawner.must_spawn(__embassy_main(spawner));
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cortex_m() -> TokenStream {
|
||||
quote! {
|
||||
#[cortex_m_rt::entry]
|
||||
fn main() -> ! {
|
||||
let mut executor = ::embassy_executor::Executor::new();
|
||||
let executor = unsafe { __make_static(&mut executor) };
|
||||
executor.run(|spawner| {
|
||||
spawner.must_spawn(__embassy_main(spawner));
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wasm() -> TokenStream {
|
||||
quote! {
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(start)]
|
||||
pub fn main() -> Result<(), wasm_bindgen::JsValue> {
|
||||
let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
|
||||
|
||||
executor.start(|spawner| {
|
||||
spawner.spawn(__embassy_main(spawner)).unwrap();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn std() -> TokenStream {
|
||||
quote! {
|
||||
fn main() -> ! {
|
||||
let mut executor = ::embassy_executor::Executor::new();
|
||||
let executor = unsafe { __make_static(&mut executor) };
|
||||
|
||||
executor.run(|spawner| {
|
||||
spawner.must_spawn(__embassy_main(spawner));
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
|
||||
#[allow(unused_variables)]
|
||||
let args = Args::from_list(args).map_err(|e| e.write_errors())?;
|
||||
|
||||
let fargs = f.sig.inputs.clone();
|
||||
|
||||
let ctxt = Ctxt::new();
|
||||
|
||||
if f.sig.asyncness.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "main function must be async");
|
||||
}
|
||||
if !f.sig.generics.params.is_empty() {
|
||||
ctxt.error_spanned_by(&f.sig, "main function must not be generic");
|
||||
}
|
||||
if !f.sig.generics.where_clause.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "main function must not have `where` clauses");
|
||||
}
|
||||
if !f.sig.abi.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "main function must not have an ABI qualifier");
|
||||
}
|
||||
if !f.sig.variadic.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "main function must not be variadic");
|
||||
}
|
||||
match &f.sig.output {
|
||||
ReturnType::Default => {}
|
||||
ReturnType::Type(_, ty) => match &**ty {
|
||||
Type::Tuple(tuple) if tuple.elems.is_empty() => {}
|
||||
Type::Never(_) => {}
|
||||
_ => ctxt.error_spanned_by(
|
||||
&f.sig,
|
||||
"main function must either not return a value, return `()` or return `!`",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
if fargs.len() != 1 {
|
||||
ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner.");
|
||||
}
|
||||
|
||||
ctxt.check()?;
|
||||
|
||||
let f_body = f.block;
|
||||
let out = &f.sig.output;
|
||||
|
||||
let result = quote! {
|
||||
#[::embassy_executor::task()]
|
||||
async fn __embassy_main(#fargs) #out {
|
||||
#f_body
|
||||
}
|
||||
|
||||
unsafe fn __make_static<T>(t: &mut T) -> &'static mut T {
|
||||
::core::mem::transmute(t)
|
||||
}
|
||||
|
||||
#main
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
2
embassy-executor-macros/src/macros/mod.rs
Normal file
2
embassy-executor-macros/src/macros/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod main;
|
||||
pub mod task;
|
114
embassy-executor-macros/src/macros/task.rs
Normal file
114
embassy-executor-macros/src/macros/task.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use darling::export::NestedMeta;
|
||||
use darling::FromMeta;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type};
|
||||
|
||||
use crate::util::ctxt::Ctxt;
|
||||
|
||||
#[derive(Debug, FromMeta)]
|
||||
struct Args {
|
||||
#[darling(default)]
|
||||
pool_size: Option<syn::Expr>,
|
||||
}
|
||||
|
||||
pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
|
||||
let args = Args::from_list(args).map_err(|e| e.write_errors())?;
|
||||
|
||||
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();
|
||||
|
||||
if f.sig.asyncness.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "task functions must be async");
|
||||
}
|
||||
if !f.sig.generics.params.is_empty() {
|
||||
ctxt.error_spanned_by(&f.sig, "task functions must not be generic");
|
||||
}
|
||||
if !f.sig.generics.where_clause.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "task functions must not have `where` clauses");
|
||||
}
|
||||
if !f.sig.abi.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "task functions must not have an ABI qualifier");
|
||||
}
|
||||
if !f.sig.variadic.is_none() {
|
||||
ctxt.error_spanned_by(&f.sig, "task functions must not be variadic");
|
||||
}
|
||||
match &f.sig.output {
|
||||
ReturnType::Default => {}
|
||||
ReturnType::Type(_, ty) => match &**ty {
|
||||
Type::Tuple(tuple) if tuple.elems.is_empty() => {}
|
||||
Type::Never(_) => {}
|
||||
_ => ctxt.error_spanned_by(
|
||||
&f.sig,
|
||||
"task functions must either not return a value, return `()` or return `!`",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
let mut arg_names = Vec::new();
|
||||
let mut fargs = f.sig.inputs.clone();
|
||||
|
||||
for arg in fargs.iter_mut() {
|
||||
match arg {
|
||||
syn::FnArg::Receiver(_) => {
|
||||
ctxt.error_spanned_by(arg, "task functions must not have receiver arguments");
|
||||
}
|
||||
syn::FnArg::Typed(t) => match t.pat.as_mut() {
|
||||
syn::Pat::Ident(id) => {
|
||||
arg_names.push(id.ident.clone());
|
||||
id.mutability = None;
|
||||
}
|
||||
_ => {
|
||||
ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.check()?;
|
||||
|
||||
let task_ident = f.sig.ident.clone();
|
||||
let task_inner_ident = format_ident!("__{}_task", task_ident);
|
||||
|
||||
let mut task_inner = f;
|
||||
let visibility = task_inner.vis.clone();
|
||||
task_inner.vis = syn::Visibility::Inherited;
|
||||
task_inner.sig.ident = task_inner_ident.clone();
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
let mut task_outer: ItemFn = parse_quote! {
|
||||
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
|
||||
type Fut = impl ::core::future::Future + 'static;
|
||||
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,)*)) }
|
||||
}
|
||||
};
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
let mut task_outer: ItemFn = parse_quote! {
|
||||
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
|
||||
const POOL_SIZE: usize = #pool_size;
|
||||
static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new();
|
||||
unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
|
||||
}
|
||||
};
|
||||
|
||||
task_outer.attrs.append(&mut task_inner.attrs.clone());
|
||||
|
||||
let result = quote! {
|
||||
// This is the user's task function, renamed.
|
||||
// We put it outside the #task_ident fn below, because otherwise
|
||||
// the items defined there (such as POOL) would be in scope
|
||||
// in the user's code.
|
||||
#[doc(hidden)]
|
||||
#task_inner
|
||||
|
||||
#task_outer
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
Reference in New Issue
Block a user