use bindgen::callbacks::{IntKind, ParseCallbacks};
use proc_macro2::Span;
use quote::quote;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Mutex;
use syn::{parse_quote, ItemMod};
#[derive(Debug, Default)]
pub(crate) struct PreprocessorDefinitions {
integral: HashMap<String, i64>,
string: HashMap<String, Vec<u8>>,
}
impl PreprocessorDefinitions {
pub fn new() -> Self {
PreprocessorDefinitions {
integral: HashMap::new(),
string: HashMap::new(),
}
}
fn insert_int_macro(&mut self, name: &str, val: i64) {
self.integral.insert(name.to_string(), val);
}
fn insert_str_macro(&mut self, name: &str, val: &[u8]) {
self.string.insert(name.to_string(), val.to_vec());
}
pub fn to_mod(&self) -> Option<ItemMod> {
if self.integral.is_empty() && self.string.is_empty() {
None
} else {
let span = Span::call_site();
let idefs = self.integral.iter().map(|(k, v)| {
let k = syn::Ident::new(k, span);
quote! {
pub const #k: i64 = #v;
}
});
let sdefs = self.string.iter().filter_map(|(k, v)| {
let k = syn::Ident::new(k, span);
String::from_utf8(v.clone()).ok().map(|v| {
quote! {
pub const #k: &'static str = #v;
}
})
});
Some(parse_quote! {
pub mod defs {
#(#idefs)*
#(#sdefs)*
}
})
}
}
}
#[derive(Debug)]
pub(crate) struct PreprocessorParseCallbacks {
definitions: Rc<Mutex<PreprocessorDefinitions>>,
}
impl PreprocessorParseCallbacks {
pub fn new(definitions: Rc<Mutex<PreprocessorDefinitions>>) -> Self {
PreprocessorParseCallbacks { definitions }
}
fn get_defs(&self) -> std::sync::MutexGuard<PreprocessorDefinitions> {
self.definitions
.try_lock()
.expect("would block whilst adding macro")
}
}
impl ParseCallbacks for PreprocessorParseCallbacks {
fn int_macro(&self, name: &str, value: i64) -> Option<IntKind> {
self.get_defs().insert_int_macro(name, value);
None
}
fn str_macro(&self, name: &str, value: &[u8]) {
self.get_defs().insert_str_macro(name, value)
}
}