Skip to content

Commit 0d20227

Browse files
author
Henrik Tjäder
committed
Extern Idle/Init
Tasks can be externally defined, so should idle and init
1 parent 64b2390 commit 0d20227

File tree

7 files changed

+200
-12
lines changed

7 files changed

+200
-12
lines changed

examples/extern_idle.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//! examples/extern_idle
2+
3+
#[mock::app(parse_binds, dispatchers = [UART1])]
4+
mod app {
5+
// idle externally implemented
6+
use crate::{bar, foo};
7+
8+
#[shared]
9+
struct Shared {
10+
a: u32,
11+
}
12+
13+
#[local]
14+
struct Local {}
15+
16+
#[init]
17+
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {}
18+
19+
extern "Rust" {
20+
// Software task
21+
#[task(shared = [a], priority = 2)]
22+
fn foo(_: foo::Context, _: u32);
23+
24+
// Hardware task
25+
#[task(binds = UART0, shared = [a], priority = 2)]
26+
// #[inline(always)] // would be rejected
27+
fn bar(_: bar::Context);
28+
29+
// Externally defined idle task
30+
#[idle()]
31+
fn idle(_: idle::Context) -> !;
32+
}
33+
}
34+
35+
// The actual functions to dispatch are
36+
// defined outside of the mod `app`.
37+
//
38+
// fn foo(_: foo::Context, _: u32) {}
39+
// fn bar(_: bar::Context, _: u32) {}
40+
// fn idle(_: idle::Context) -> ! {}

examples/extern_init.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! examples/extern_init
2+
3+
#[mock::app(parse_binds, dispatchers = [UART1])]
4+
mod app {
5+
// init externally implemented
6+
use crate::{bar, foo, init, idle};
7+
8+
#[shared]
9+
struct Shared {
10+
a: u32,
11+
}
12+
13+
#[local]
14+
struct Local {}
15+
16+
#[idle]
17+
fn idle(_: idle::Context) -> ! {}
18+
19+
20+
extern "Rust" {
21+
22+
// Externally defined init
23+
#[init]
24+
fn init(_: init::Context) -> (Shared, Local, init::Monotonics);
25+
26+
// Software task
27+
#[task(shared = [a], priority = 2)]
28+
fn foo(_: foo::Context, _: u32);
29+
30+
// Hardware task
31+
#[task(binds = UART0, shared = [a], priority = 2)]
32+
//#[inline(always)] // would be rejected
33+
fn bar(_: bar::Context);
34+
}
35+
}
36+
37+
// The actual functions to dispatch are
38+
// defined outside of the mod `app`.
39+
//
40+
// fn foo(_: foo::Context, _: u32) {}
41+
// fn bar(_: bar::Context, _: u32) {}
42+
// fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {}

src/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ pub struct Init {
9090

9191
/// The name of the user provided local resources struct
9292
pub user_local_struct: Ident,
93+
94+
/// The task is declared externally
95+
pub is_extern: bool,
9396
}
9497

9598
/// `init` context metadata
@@ -126,6 +129,9 @@ pub struct Idle {
126129

127130
/// The statements that make up this `idle` function
128131
pub stmts: Vec<Stmt>,
132+
133+
/// The task is declared externally
134+
pub is_extern: bool,
129135
}
130136

131137
/// `idle` context metadata

src/parse/app.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,46 @@ impl App {
383383
for item in mod_.items {
384384
if let ForeignItem::Fn(mut item) = item {
385385
let span = item.sig.ident.span();
386+
// Find externally defined #[init] tasks
386387
if let Some(pos) = item
388+
.attrs
389+
.iter()
390+
.position(|attr| util::attr_eq(attr, "init"))
391+
{
392+
let args = InitArgs::parse(item.attrs.remove(pos).tokens)?;
393+
394+
// If an init function already exists, error
395+
if init.is_some() {
396+
return Err(parse::Error::new(
397+
span,
398+
"`#[init]` function must appear at most once",
399+
));
400+
}
401+
402+
check_ident(&item.sig.ident)?;
403+
404+
init = Some(Init::parse_foreign(args, item.clone())?);
405+
406+
// Find externally defined #[idle] tasks
407+
} else if let Some(pos) = item
408+
.attrs
409+
.iter()
410+
.position(|attr| util::attr_eq(attr, "idle"))
411+
{
412+
let args = IdleArgs::parse(item.attrs.remove(pos).tokens)?;
413+
414+
// If an idle function already exists, error
415+
if idle.is_some() {
416+
return Err(parse::Error::new(
417+
span,
418+
"`#[idle]` function must appear at most once",
419+
));
420+
}
421+
422+
check_ident(&item.sig.ident)?;
423+
424+
idle = Some(Idle::parse_foreign(args, item.clone())?);
425+
} else if let Some(pos) = item
387426
.attrs
388427
.iter()
389428
.position(|attr| util::attr_eq(attr, "task"))
@@ -400,7 +439,7 @@ impl App {
400439
if item.attrs.len() != 1 {
401440
return Err(parse::Error::new(
402441
span,
403-
"`extern` task required `#[task(..)]` attribute",
442+
"`extern` tasks only supports one attribute: `#[task(..)]`",
404443
));
405444
}
406445

@@ -430,14 +469,10 @@ impl App {
430469
} else {
431470
return Err(parse::Error::new(
432471
span,
433-
"`extern` task required `#[task(..)]` attribute",
472+
"`extern` task, init or idle must have either `#[task(..)]`,
473+
`#[init(..)]` or `#[idle(..)]` attribute",
434474
));
435475
}
436-
} else {
437-
return Err(parse::Error::new(
438-
item.span(),
439-
"this item must live outside the `#[app]` module",
440-
));
441476
}
442477
}
443478
}

src/parse/hardware_task.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ impl HardwareTask {
4747
),
4848
))
4949
}
50-
}
51-
52-
impl HardwareTask {
5350
pub(crate) fn parse_foreign(
5451
args: HardwareTaskArgs,
5552
item: ForeignItemFn,

src/parse/idle.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use proc_macro2::TokenStream as TokenStream2;
2-
use syn::{parse, ItemFn};
2+
use syn::{parse, ForeignItemFn, Stmt, ItemFn};
33

44
use crate::{
55
ast::{Idle, IdleArgs},
@@ -29,6 +29,37 @@ impl Idle {
2929
context,
3030
name: item.sig.ident,
3131
stmts: item.block.stmts,
32+
is_extern: false,
33+
});
34+
}
35+
}
36+
}
37+
38+
Err(parse::Error::new(
39+
item.sig.ident.span(),
40+
&format!(
41+
"this `#[idle]` function must have signature `fn({}::Context) -> !`",
42+
name
43+
),
44+
))
45+
}
46+
pub(crate) fn parse_foreign(args: IdleArgs, item: ForeignItemFn) -> parse::Result<Self> {
47+
let valid_signature = util::check_foreign_fn_signature(&item)
48+
&& item.sig.inputs.len() == 1
49+
&& util::type_is_bottom(&item.sig.output);
50+
51+
let name = item.sig.ident.to_string();
52+
53+
if valid_signature {
54+
if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) {
55+
if rest.is_empty() {
56+
return Ok(Idle {
57+
args,
58+
attrs: item.attrs,
59+
context,
60+
name: item.sig.ident,
61+
stmts: Vec::<Stmt>::new(),
62+
is_extern: true,
3263
});
3364
}
3465
}

src/parse/init.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use proc_macro2::TokenStream as TokenStream2;
22

3-
use syn::{parse, ItemFn};
3+
use syn::{parse, ForeignItemFn, ItemFn, Stmt};
44

55
use crate::{
66
ast::{Init, InitArgs},
@@ -35,6 +35,43 @@ impl Init {
3535
stmts: item.block.stmts,
3636
user_shared_struct,
3737
user_local_struct,
38+
is_extern: false,
39+
});
40+
}
41+
}
42+
}
43+
}
44+
45+
Err(parse::Error::new(
46+
span,
47+
&format!(
48+
"the `#[init]` function must have signature `fn({}::Context) -> (Shared resources struct, Local resources struct, {0}::Monotonics)`",
49+
name
50+
),
51+
))
52+
}
53+
pub(crate) fn parse_foreign(args: InitArgs, item: ForeignItemFn) -> parse::Result<Self> {
54+
let valid_signature = util::check_foreign_fn_signature(&item) && item.sig.inputs.len() == 1;
55+
56+
let span = item.sig.ident.span();
57+
58+
let name = item.sig.ident.to_string();
59+
60+
if valid_signature {
61+
if let Ok((user_shared_struct, user_local_struct)) =
62+
util::type_is_init_return(&item.sig.output, &name)
63+
{
64+
if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) {
65+
if rest.is_empty() {
66+
return Ok(Init {
67+
args,
68+
attrs: item.attrs,
69+
context,
70+
name: item.sig.ident,
71+
stmts: Vec::<Stmt>::new(),
72+
user_shared_struct,
73+
user_local_struct,
74+
is_extern: true,
3875
});
3976
}
4077
}

0 commit comments

Comments
 (0)