use std::{
collections::hash_map::DefaultHasher,
hash::{Hash as _, Hasher as _},
};
use proc_macro::Span;
use proc_macro2::{Ident as Ident2, Span as Span2, TokenStream as TokenStream2};
use quote::{format_ident, quote};
use syn::{parse_quote, Expr, Ident, LitStr};
pub(crate) use symbol::mangled as mangled_symbol_name;
mod symbol;
pub(crate) fn crate_local_disambiguator() -> u64 {
hash(&format!("{:?}", Span::call_site()))
}
pub(crate) fn escaped_expr_string(expr: &Expr) -> String {
quote!(#expr)
.to_string()
.replace('{', "{{")
.replace('}', "}}")
}
pub(crate) fn interned_string(string: &str, tag: &str, is_log_statement: bool) -> TokenStream2 {
let var_name = if is_log_statement {
format_ident!("DEFMT_LOG_STATEMENT")
} else {
format_ident!("S")
};
let var_addr = if cfg!(feature = "unstable-test") {
quote!({ defmt::export::fetch_add_string_index() })
} else {
let var_item = static_variable(&var_name, string, tag);
quote!({
#var_item
&#var_name as *const u8 as u16
})
};
quote!({
defmt::export::make_istr(#var_addr)
})
}
pub(crate) fn linker_section(for_macos: bool, prefix: Option<&str>, symbol: &str) -> String {
let mut sub_section = if let Some(prefix) = prefix {
format!(".{prefix}.{symbol}")
} else {
format!(".{symbol}")
};
if for_macos {
sub_section = format!(",{:x}", hash(&sub_section));
}
format!(".defmt{sub_section}")
}
pub(crate) fn static_variable(name: &Ident2, data: &str, tag: &str) -> TokenStream2 {
let sym_name = mangled_symbol_name(tag, data);
let section = linker_section(false, None, &sym_name);
let section_for_macos = linker_section(true, None, &sym_name);
quote!(
#[cfg_attr(target_os = "macos", link_section = #section_for_macos)]
#[cfg_attr(not(target_os = "macos"), link_section = #section)]
#[export_name = #sym_name]
static #name: u8 = 0;
)
}
pub(crate) fn string_literal(content: &str) -> LitStr {
LitStr::new(content, Span2::call_site())
}
pub(crate) fn variable(name: &str) -> Expr {
let ident = Ident::new(name, Span2::call_site());
parse_quote!(#ident)
}
fn hash(string: &str) -> u64 {
let mut hasher = DefaultHasher::new();
string.hash(&mut hasher);
hasher.finish()
}