diff options
author | 2021-07-09 11:00:11 +0000 | |
---|---|---|
committer | 2021-07-09 11:00:11 +0000 | |
commit | e1a4d001f8e724596cd9de3e90698ce7de473b3f (patch) | |
tree | f7aac5eae4cc2e19cc06bfd6fa8dab843dcfb276 /macros/src/codegen/local_resources_struct.rs | |
parent | 13dc3992e616d817e38c167c4b47db816855f18b (diff) | |
parent | f3d9fd9b638a25b497e1ca02e7ce5de86c9fc1c9 (diff) | |
download | rtic-e1a4d001f8e724596cd9de3e90698ce7de473b3f.tar.gz rtic-e1a4d001f8e724596cd9de3e90698ce7de473b3f.tar.zst rtic-e1a4d001f8e724596cd9de3e90698ce7de473b3f.zip |
Merge #494
494: Resoures take 2 r=korken89 a=korken89
Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
Diffstat (limited to 'macros/src/codegen/local_resources_struct.rs')
-rw-r--r-- | macros/src/codegen/local_resources_struct.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/macros/src/codegen/local_resources_struct.rs b/macros/src/codegen/local_resources_struct.rs new file mode 100644 index 00000000..4bd9e2a4 --- /dev/null +++ b/macros/src/codegen/local_resources_struct.rs @@ -0,0 +1,110 @@ +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use rtic_syntax::{ + ast::{App, TaskLocal}, + Context, +}; + +use crate::codegen::util; + +/// Generates local resources structs +pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, TokenStream2) { + let mut lt = None; + + let resources = match ctxt { + Context::Init => &app.init.args.local_resources, + Context::Idle => &app.idle.as_ref().unwrap().args.local_resources, + Context::HardwareTask(name) => &app.hardware_tasks[name].args.local_resources, + Context::SoftwareTask(name) => &app.software_tasks[name].args.local_resources, + }; + + let task_name = util::get_task_name(ctxt, app); + + let mut fields = vec![]; + let mut values = vec![]; + let mut has_cfgs = false; + + for (name, task_local) in resources { + let (cfgs, ty, is_declared) = match task_local { + TaskLocal::External => { + let r = app.local_resources.get(name).expect("UNREACHABLE"); + (&r.cfgs, &r.ty, false) + } + TaskLocal::Declared(r) => (&r.cfgs, &r.ty, true), + _ => unreachable!(), + }; + + has_cfgs |= !cfgs.is_empty(); + + let lt = if ctxt.runs_once() { + quote!('static) + } else { + lt = Some(quote!('a)); + quote!('a) + }; + + let mangled_name = if matches!(task_local, TaskLocal::External) { + util::mark_internal_ident(&util::static_local_resource_ident(name)) + } else { + util::mark_internal_ident(&util::declared_static_local_resource_ident( + name, &task_name, + )) + }; + + fields.push(quote!( + #(#cfgs)* + pub #name: &#lt mut #ty + )); + + let expr = if is_declared { + // If the local resources is already initialized, we only need to access its value and + // not go through an `MaybeUninit` + quote!(#mangled_name.get_mut_unchecked()) + } else { + quote!(&mut *#mangled_name.get_mut_unchecked().as_mut_ptr()) + }; + + values.push(quote!( + #(#cfgs)* + #name: #expr + )); + } + + if lt.is_some() { + *needs_lt = true; + + // The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused + if has_cfgs { + fields.push(quote!( + #[doc(hidden)] + pub __marker__: core::marker::PhantomData<&'a ()> + )); + + values.push(quote!(__marker__: core::marker::PhantomData)) + } + } + + let doc = format!("Local resources `{}` has access to", ctxt.ident(app)); + let ident = util::local_resources_ident(ctxt, app); + let ident = util::mark_internal_ident(&ident); + let item = quote!( + #[allow(non_snake_case)] + #[doc = #doc] + pub struct #ident<#lt> { + #(#fields,)* + } + ); + + let constructor = quote!( + impl<#lt> #ident<#lt> { + #[inline(always)] + pub unsafe fn new() -> Self { + #ident { + #(#values,)* + } + } + } + ); + + (item, constructor) +} |