rtic_macros/codegen/
util.rs

1use crate::syntax::{ast::App, Context};
2use core::sync::atomic::{AtomicUsize, Ordering};
3use proc_macro2::{Span, TokenStream as TokenStream2};
4use quote::quote;
5use syn::{Ident, PatType};
6
7const RTIC_INTERNAL: &str = "__rtic_internal";
8
9/// Mark a name as internal
10pub fn mark_internal_name(name: &str) -> Ident {
11    Ident::new(&format!("{RTIC_INTERNAL}_{name}"), Span::call_site())
12}
13
14/// Generate an internal identifier for tasks
15pub fn internal_task_ident(task: &Ident, ident_name: &str) -> Ident {
16    mark_internal_name(&format!("{task}_{ident_name}"))
17}
18
19fn link_section_index() -> usize {
20    static INDEX: AtomicUsize = AtomicUsize::new(0);
21
22    INDEX.fetch_add(1, Ordering::Relaxed)
23}
24
25/// Add `link_section` attribute
26pub fn link_section_uninit() -> TokenStream2 {
27    let section = format!(".uninit.rtic{}", link_section_index());
28
29    quote!(#[link_section = #section])
30}
31
32/// Regroups the inputs of a task
33///
34/// `inputs` could be &[`input: Foo`] OR &[`mut x: i32`, `ref y: i64`]
35pub fn regroup_inputs(
36    inputs: &[PatType],
37) -> (
38    // args e.g. &[`_0`],  &[`_0: i32`, `_1: i64`]
39    Vec<TokenStream2>,
40    // tupled e.g. `_0`, `(_0, _1)`
41    TokenStream2,
42    // untupled e.g. &[`_0`], &[`_0`, `_1`]
43    Vec<TokenStream2>,
44    // ty e.g. `Foo`, `(i32, i64)`
45    TokenStream2,
46) {
47    if inputs.len() == 1 {
48        let ty = &inputs[0].ty;
49
50        (
51            vec![quote!(_0: #ty)],
52            quote!(_0),
53            vec![quote!(_0)],
54            quote!(#ty),
55        )
56    } else {
57        let mut args = vec![];
58        let mut pats = vec![];
59        let mut tys = vec![];
60
61        for (i, input) in inputs.iter().enumerate() {
62            let i = Ident::new(&format!("_{i}"), Span::call_site());
63            let ty = &input.ty;
64
65            args.push(quote!(#i: #ty));
66
67            pats.push(quote!(#i));
68
69            tys.push(quote!(#ty));
70        }
71
72        let tupled = {
73            let pats = pats.clone();
74            quote!((#(#pats,)*))
75        };
76        let ty = quote!((#(#tys,)*));
77        (args, tupled, pats, ty)
78    }
79}
80
81/// Get the ident for the name of the task
82pub fn get_task_name(ctxt: Context, app: &App) -> Ident {
83    let s = match ctxt {
84        Context::Init => app.init.name.to_string(),
85        Context::Idle => app
86            .idle
87            .as_ref()
88            .expect("RTIC-ICE: unable to find idle name")
89            .name
90            .to_string(),
91        Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
92    };
93
94    Ident::new(&s, Span::call_site())
95}
96
97/// Generates a pre-reexport identifier for the "shared resources" struct
98pub fn shared_resources_ident(ctxt: Context, app: &App) -> Ident {
99    let mut s = match ctxt {
100        Context::Init => app.init.name.to_string(),
101        Context::Idle => app
102            .idle
103            .as_ref()
104            .expect("RTIC-ICE: unable to find idle name")
105            .name
106            .to_string(),
107        Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
108    };
109
110    s.push_str("SharedResources");
111
112    mark_internal_name(&s)
113}
114
115/// Generates a pre-reexport identifier for the "local resources" struct
116pub fn local_resources_ident(ctxt: Context, app: &App) -> Ident {
117    let mut s = match ctxt {
118        Context::Init => app.init.name.to_string(),
119        Context::Idle => app
120            .idle
121            .as_ref()
122            .expect("RTIC-ICE: unable to find idle name")
123            .name
124            .to_string(),
125        Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
126    };
127
128    s.push_str("LocalResources");
129
130    mark_internal_name(&s)
131}
132
133/// Suffixed identifier
134pub fn suffixed(name: &str) -> Ident {
135    let span = Span::call_site();
136    Ident::new(name, span)
137}
138
139pub fn static_shared_resource_ident(name: &Ident) -> Ident {
140    mark_internal_name(&format!("shared_resource_{name}"))
141}
142
143pub fn static_local_resource_ident(name: &Ident) -> Ident {
144    mark_internal_name(&format!("local_resource_{name}"))
145}
146
147pub fn declared_static_local_resource_ident(name: &Ident, task_name: &Ident) -> Ident {
148    mark_internal_name(&format!("local_{task_name}_{name}"))
149}
150
151pub fn need_to_lock_ident(name: &Ident) -> Ident {
152    Ident::new(&format!("{name}_that_needs_to_be_locked"), name.span())
153}
154
155pub fn zero_prio_dispatcher_ident() -> Ident {
156    Ident::new("__rtic_internal_async_0_prio_dispatcher", Span::call_site())
157}
158
159/// The name to get better RT flag errors
160pub fn rt_err_ident() -> Ident {
161    Ident::new(
162        "you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml",
163        Span::call_site(),
164    )
165}
166
167pub fn from_ptr_n_args_ident(n: usize) -> Ident {
168    Ident::new(&format!("from_ptr_{}_args", n + 1), Span::call_site())
169}
170
171pub fn new_n_args_ident(n: usize) -> Ident {
172    Ident::new(&format!("new_{}_args", n + 1), Span::call_site())
173}