mod defs;
use proc_macro::{TokenStream};
use proc_macro2::Ident;
use quote::{format_ident, quote, ToTokens};
use syn::{ExprStruct, parse_macro_input, parse_quote, Path};
use syn::parse::{Parse, ParseStream};
use syn::token::{Colon};
#[proc_macro]
pub fn define_header(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ExprStruct);
let ident = input.path;
let ident_str = ident.to_token_stream().to_string().trim_matches('"').to_string();
let fields = input.fields;
let link_section = ".emcell.cur_header";
let static_ident = format_ident!("_emcell_{}_internal", ident_str);
let output: proc_macro2::TokenStream = {
quote!(
#[cortex_m_rt::entry]
fn _emcell_internal_main() -> ! {
let reset_vec_addr = unsafe { (<#ident as emcell::Cell>::DEVICE_CONFIG.flash_range_start as *const u32)
.offset(1)} ;
let reset_vec = unsafe { reset_vec_addr.read_volatile() } as *const u32;
let reset_vec = unsafe { core::mem::transmute::<_, fn() -> !>(reset_vec) };
unsafe {reset_vec()}
}
#[no_mangle]
#[link_section = #link_section]
pub static #static_ident : #ident = #ident {
signature: 0xdeadbeef,
init: unsafe { __emcell_init },
#fields
};
unsafe fn __emcell_init(known_sha: [u8; 32], init_memory: bool) -> bool {
if known_sha != <#ident as emcell::Cell>::CUR_META.struct_sha256 {
return false;
}
if (init_memory) {
emcell::device::init();
}
true
}
)
};
proc_macro::TokenStream::from(output)
}
#[proc_macro]
pub fn define_primary_header(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ExprStruct);
let ident = input.path;
let ident_str = ident.to_token_stream().to_string().trim_matches('"').to_string();
let fields = input.fields;
let link_section = ".emcell.cur_header";
let static_ident = format_ident!("_emcell_{}_internal", ident_str);
let output: proc_macro2::TokenStream = {
quote!(
#[no_mangle]
#[link_section = #link_section]
pub static #static_ident : #ident = #ident {
signature: 0xbeef_dead,
init: unsafe { __emcell_init_primary },
#fields
};
unsafe fn __emcell_init_primary(known_sha: [u8; 32], _init_memory: bool) -> bool {
if known_sha != <#ident as emcell::Cell>::CUR_META.struct_sha256 {
return false;
}
true
}
)
};
proc_macro::TokenStream::from(output)
}
struct ExternHeader {
name: Ident,
typez: Ident,
}
impl Parse for ExternHeader {
fn parse(input: ParseStream) -> syn::Result<Self> {
let left: Ident = input.parse()?;
let _: Colon = input.parse()?;
let right: Ident = input.parse()?;
Ok(ExternHeader { name: left, typez: right })
}
}
fn generate_extern_header(cell_name: Ident, cell_type: Ident, forward_or_backward: Path) -> TokenStream {
let internal_ident = format_ident!("_emcell_{}_internal", cell_type);
let output: proc_macro2::TokenStream = {
quote!(
extern crate emcell;
extern "Rust" {
pub static #internal_ident: #cell_type;
}
pub struct #cell_name {
inner: emcell::CellWrapper<#cell_type, #forward_or_backward>
}
impl #cell_name {
pub fn new() -> Option<Self> {
let cell = unsafe { & #internal_ident };
unsafe { emcell::CellWrapper::<#cell_type, #forward_or_backward>::_new_init(cell)}.map(|inner| Self { inner })
}
pub const fn new_uninit() -> Self {
let cell = unsafe { & #internal_ident };
let inner = unsafe { emcell::CellWrapper::_new_uninit(cell) };
Self {
inner
}
}
pub const fn new_dummy(dummy_header: &'static #cell_type) -> Self {
Self {
inner: emcell::CellWrapper::new_dummy(dummy_header)
}
}
pub fn ensure_init(&self) -> Option<()> {
self.inner.ensure_init()
}
pub fn is_dummy(&self) -> bool {
self.inner.is_dummy()
}
}
impl core::ops::Deref for #cell_name {
type Target = #cell_type;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
)
};
proc_macro::TokenStream::from(output)
}
#[proc_macro]
pub fn extern_header_forward(item: TokenStream) -> TokenStream {
let ExternHeader { name: cell_name, typez: cell_type } = parse_macro_input!(item as ExternHeader);
let forward_backward = parse_quote!(emcell::Forward);
generate_extern_header(cell_name, cell_type, forward_backward)
}
#[proc_macro]
pub fn extern_header_backward(item: TokenStream) -> TokenStream {
let ExternHeader { name: cell_name, typez: cell_type } = parse_macro_input!(item as ExternHeader);
let forward_backward = parse_quote!(emcell::Backward);
generate_extern_header(cell_name, cell_type, forward_backward)
}
#[proc_macro_attribute]
pub fn cell(cell_attr: TokenStream, item: TokenStream) -> TokenStream {
defs::cell(cell_attr, item)
}
#[proc_macro_attribute]
pub fn ram_region(attr: TokenStream, item: TokenStream) -> TokenStream {
defs::ram_region(attr, item)
}
#[proc_macro_attribute]
pub fn flash_region(attr: TokenStream, item: TokenStream) -> TokenStream {
defs::flash_region(attr, item)
}
#[proc_macro_attribute]
pub fn switch_vectors(attr: TokenStream, item: TokenStream) -> TokenStream {
defs::switch_vectors(attr, item)
}
#[proc_macro]
pub fn device(item: TokenStream) -> TokenStream {
defs::device(item)
}
#[proc_macro]
pub fn emcell_configuration(input: TokenStream) -> TokenStream {
defs::emcell_configuration(input)
}