rtic_macros/codegen/
local_resources_struct.rs

1use crate::syntax::{
2    ast::{App, TaskLocal},
3    Context,
4};
5use proc_macro2::TokenStream as TokenStream2;
6use quote::quote;
7
8use crate::codegen::util;
9
10/// Generates local resources structs
11pub fn codegen(ctxt: Context, app: &App) -> (TokenStream2, TokenStream2) {
12    let resources = match ctxt {
13        Context::Init => &app.init.args.local_resources,
14        Context::Idle => {
15            &app.idle
16                .as_ref()
17                .expect("RTIC-ICE: unable to get idle name")
18                .args
19                .local_resources
20        }
21        Context::HardwareTask(name) => &app.hardware_tasks[name].args.local_resources,
22        Context::SoftwareTask(name) => &app.software_tasks[name].args.local_resources,
23    };
24
25    let task_name = util::get_task_name(ctxt, app);
26
27    let mut fields = vec![];
28    let mut values = vec![];
29
30    for (name, task_local) in resources {
31        let (cfgs, ty, is_declared) = match task_local {
32            TaskLocal::External => {
33                let r = app.local_resources.get(name).expect("UNREACHABLE");
34                (&r.cfgs, &r.ty, false)
35            }
36            TaskLocal::Declared(r) => (&r.cfgs, &r.ty, true),
37        };
38
39        let lt = if ctxt.runs_once() {
40            quote!('static)
41        } else {
42            quote!('a)
43        };
44
45        let mangled_name = if matches!(task_local, TaskLocal::External) {
46            util::static_local_resource_ident(name)
47        } else {
48            util::declared_static_local_resource_ident(name, &task_name)
49        };
50
51        fields.push(quote!(
52            #(#cfgs)*
53            #[allow(missing_docs)]
54            pub #name: &#lt mut #ty
55        ));
56
57        let expr = if is_declared {
58            // If the local resources is already initialized, we only need to access its value and
59            // not go through an `MaybeUninit`
60            quote!(&mut *#mangled_name.get_mut())
61        } else {
62            quote!(&mut *(&mut *#mangled_name.get_mut()).as_mut_ptr())
63        };
64
65        values.push(quote!(
66            #(#cfgs)*
67            #name: #expr
68        ));
69    }
70
71    fields.push(quote!(
72        #[doc(hidden)]
73        pub __rtic_internal_marker: ::core::marker::PhantomData<&'a ()>
74    ));
75
76    values.push(quote!(__rtic_internal_marker: ::core::marker::PhantomData));
77
78    let doc = format!("Local resources `{}` has access to", ctxt.ident(app));
79    let ident = util::local_resources_ident(ctxt, app);
80    let item = quote!(
81        #[allow(non_snake_case)]
82        #[allow(non_camel_case_types)]
83        #[doc = #doc]
84        pub struct #ident<'a> {
85            #(#fields,)*
86        }
87    );
88
89    let constructor = quote!(
90        impl<'a> #ident<'a> {
91            #[inline(always)]
92            #[allow(missing_docs)]
93            pub unsafe fn new() -> Self {
94                #ident {
95                    #(#values,)*
96                }
97            }
98        }
99    );
100
101    (item, constructor)
102}