allow init and idle to be externed

This commit is contained in:
Vixu 2023-06-08 13:44:49 +02:00
parent 5997938293
commit a7653cc050
7 changed files with 172 additions and 47 deletions

View file

@ -91,6 +91,9 @@ pub struct Init {
/// The name of the user provided local resources struct
pub user_local_struct: Ident,
/// The init function is declared externally
pub is_extern: bool,
}
/// `init` context metadata
@ -127,6 +130,9 @@ pub struct Idle {
/// The statements that make up this `idle` function
pub stmts: Vec<Stmt>,
/// The idle function is declared externally
pub is_extern: bool,
}
/// `idle` context metadata

View file

@ -365,6 +365,42 @@ impl App {
if let ForeignItem::Fn(mut item) = item {
let span = item.sig.ident.span();
if let Some(pos) = item
.attrs
.iter()
.position(|attr| util::attr_eq(attr, "init"))
{
let args = InitArgs::parse(item.attrs.remove(pos).tokens)?;
// If an init function already exists, error
if init.is_some() {
return Err(parse::Error::new(
span,
"`#[init]` function must appear at most once",
));
}
check_ident(&item.sig.ident)?;
init = Some(Init::parse_foreign(args, item)?);
} else if let Some(pos) = item
.attrs
.iter()
.position(|attr| util::attr_eq(attr, "idle"))
{
let args = IdleArgs::parse(item.attrs.remove(pos).tokens)?;
// If an idle function already exists, error
if idle.is_some() {
return Err(parse::Error::new(
span,
"`#[idle]` function must appear at most once",
));
}
check_ident(&item.sig.ident)?;
idle = Some(Idle::parse_foreign(args, item)?);
} else if let Some(pos) = item
.attrs
.iter()
.position(|attr| util::attr_eq(attr, "task"))
@ -408,7 +444,8 @@ impl App {
} else {
return Err(parse::Error::new(
span,
"`extern` task required `#[task(..)]` attribute",
"`extern` task, init or idle must have either `#[task(..)]`,
`#[init(..)]` or `#[idle(..)]` attribute",
));
}
} else {

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2;
use syn::{parse, ItemFn};
use syn::{parse, ForeignItemFn, ItemFn, Stmt};
use crate::syntax::{
ast::{Idle, IdleArgs},
@ -29,6 +29,35 @@ impl Idle {
context,
name: item.sig.ident,
stmts: item.block.stmts,
is_extern: false,
});
}
}
}
Err(parse::Error::new(
item.sig.ident.span(),
format!("this `#[idle]` function must have signature `fn({name}::Context) -> !`"),
))
}
pub(crate) fn parse_foreign(args: IdleArgs, item: ForeignItemFn) -> parse::Result<Self> {
let valid_signature = util::check_foreign_fn_signature(&item, false)
&& item.sig.inputs.len() == 1
&& util::type_is_bottom(&item.sig.output);
let name = item.sig.ident.to_string();
if valid_signature {
if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) {
if rest.is_empty() {
return Ok(Idle {
args,
attrs: item.attrs,
context,
name: item.sig.ident,
stmts: Vec::<Stmt>::new(),
is_extern: true,
});
}
}

View file

@ -1,6 +1,6 @@
use proc_macro2::TokenStream as TokenStream2;
use syn::{parse, ItemFn};
use syn::{parse, ForeignItemFn, ItemFn, Stmt};
use crate::syntax::{
ast::{Init, InitArgs},
@ -35,6 +35,44 @@ impl Init {
stmts: item.block.stmts,
user_shared_struct,
user_local_struct,
is_extern: false,
});
}
}
}
}
Err(parse::Error::new(
span,
format!(
"the `#[init]` function must have signature `fn({name}::Context) -> (Shared resources struct, Local resources struct)`"
),
))
}
pub(crate) fn parse_foreign(args: InitArgs, item: ForeignItemFn) -> parse::Result<Self> {
let valid_signature =
util::check_foreign_fn_signature(&item, false) && item.sig.inputs.len() == 1;
let span = item.sig.ident.span();
let name = item.sig.ident.to_string();
if valid_signature {
if let Ok((user_shared_struct, user_local_struct)) =
util::type_is_init_return(&item.sig.output)
{
if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) {
if rest.is_empty() {
return Ok(Init {
args,
attrs: item.attrs,
context,
name: item.sig.ident,
stmts: Vec::<Stmt>::new(),
user_shared_struct,
user_local_struct,
is_extern: true,
});
}
}