cortex_m_rtic_macros/codegen/
shared_resources_struct.rs
1use proc_macro2::TokenStream as TokenStream2;
2use quote::quote;
3use rtic_syntax::{ast::App, Context};
4
5use crate::codegen::util;
6
7pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, TokenStream2) {
9 let mut lt = None;
10
11 let resources = match ctxt {
12 Context::Init => unreachable!("Tried to generate shared resources struct for init"),
13 Context::Idle => &app.idle.as_ref().unwrap().args.shared_resources,
14 Context::HardwareTask(name) => &app.hardware_tasks[name].args.shared_resources,
15 Context::SoftwareTask(name) => &app.software_tasks[name].args.shared_resources,
16 };
17
18 let v = Vec::new();
19 let task_cfgs = match ctxt {
20 Context::HardwareTask(t) => {
21 &app.hardware_tasks[t].cfgs
22 }
24 Context::SoftwareTask(t) => {
25 &app.software_tasks[t].cfgs
26 }
28 _ => &v,
29 };
30
31 let mut fields = vec![];
32 let mut values = vec![];
33 let mut has_cfgs = false;
34
35 for (name, access) in resources {
36 let res = app.shared_resources.get(name).expect("UNREACHABLE");
37
38 let cfgs = &res.cfgs;
39 has_cfgs |= !cfgs.is_empty();
40
41 let mut_ = if access.is_exclusive() {
43 Some(quote!(mut))
44 } else {
45 None
46 };
47 let ty = &res.ty;
48 let mangled_name = util::static_shared_resource_ident(name);
49 let shared_name = util::need_to_lock_ident(name);
50
51 if res.properties.lock_free {
52 let lt = if ctxt.runs_once() {
54 quote!('static)
55 } else {
56 lt = Some(quote!('a));
57 quote!('a)
58 };
59
60 let lock_free_resource_doc = format!(" Lock free resource `{name}`");
61 fields.push(quote!(
62 #[doc = #lock_free_resource_doc]
63 #(#cfgs)*
64 pub #name: &#lt #mut_ #ty
65 ));
66 } else if access.is_shared() {
67 lt = Some(quote!('a));
68
69 let shared_resource_doc = format!(" Shared resource `{name}`");
70 fields.push(quote!(
71 #[doc = #shared_resource_doc]
72 #(#cfgs)*
73 pub #name: &'a #ty
74 ));
75 } else {
76 lt = Some(quote!('a));
78
79 let resource_doc =
80 format!(" Resource proxy resource `{name}`. Use method `.lock()` to gain access");
81 fields.push(quote!(
82 #[doc = #resource_doc]
83 #(#cfgs)*
84 pub #name: shared_resources::#shared_name<'a>
85 ));
86
87 values.push(quote!(
88 #[doc(hidden)]
89 #(#cfgs)*
90 #name: shared_resources::#shared_name::new(priority)
91
92 ));
93
94 continue;
96 }
97
98 let resource_doc;
99 let expr = if access.is_exclusive() {
100 resource_doc = format!(" Exclusive access resource `{name}`");
101 quote!(&mut *(&mut *#mangled_name.get_mut()).as_mut_ptr())
102 } else {
103 resource_doc = format!(" Non-exclusive access resource `{name}`");
104 quote!(&*(&*#mangled_name.get()).as_ptr())
105 };
106
107 values.push(quote!(
108 #[doc = #resource_doc]
109 #(#cfgs)*
110 #name: #expr
111 ));
112 }
113
114 if lt.is_some() {
115 *needs_lt = true;
116
117 if has_cfgs {
119 fields.push(quote!(
120 #[doc(hidden)]
121 pub __marker__: core::marker::PhantomData<&'a ()>
122 ));
123
124 values.push(quote!(__marker__: core::marker::PhantomData));
125 }
126 }
127
128 let doc = format!(" Shared resources `{}` has access to", ctxt.ident(app));
129 let ident = util::shared_resources_ident(ctxt, app);
130 let item = quote!(
131 #[allow(non_snake_case)]
132 #[allow(non_camel_case_types)]
133 #[doc = #doc]
134 #(#task_cfgs)*
135 pub struct #ident<#lt> {
136 #(#fields,)*
137 }
138 );
139
140 let arg = if ctxt.is_init() {
141 None
142 } else {
143 Some(quote!(priority: &#lt rtic::export::Priority))
144 };
145 let constructor = quote!(
146 #(#task_cfgs)*
147 impl<#lt> #ident<#lt> {
148 #[doc(hidden)]
149 #[inline(always)]
150 pub unsafe fn new(#arg) -> Self {
151 #ident {
152 #(#values,)*
153 }
154 }
155 }
156 );
157
158 (item, constructor)
159}