use crate::*;
thread_local! {
pub(crate) static INCREMENTAL: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
pub(crate) fn cache_schema(include_tests: bool) -> String {
format!("scan-{}/rev6/tests={}", env!("CARGO_PKG_VERSION"), include_tests)
}
pub(crate) fn fnv1a(bytes: &[u8]) -> String {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for &b in bytes {
h ^= b as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
format!("{h:016x}")
}
#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
pub(crate) struct FileDecls {
pub(crate) fields: FieldIndex,
pub(crate) field_elem: FieldElemIndex,
pub(crate) rets: HashMap<String, Option<String>>,
pub(crate) enum_tmp: HashMap<String, Option<String>>,
pub(crate) trait_impls: TraitImplIndex,
pub(crate) trait_decls: HashMap<String, (usize, Vec<String>)>,
pub(crate) trait_fields: TraitFieldIndex,
pub(crate) prim_aliases: Vec<String>,
pub(crate) extern_fns: Vec<String>,
pub(crate) drop_types: Vec<String>,
#[serde(default)]
pub(crate) deref_target: HashMap<String, String>,
#[serde(default)]
pub(crate) lazy_statics: Vec<String>,
}
pub(crate) fn file_decls(items: &[syn::Item], include_tests: bool) -> FileDecls {
let mut uses = HashMap::new();
let mut fields = HashMap::new();
let mut field_elem = HashMap::new();
let mut rets = HashMap::new();
let mut enum_tmp = HashMap::new();
let mut trait_impls = HashMap::new();
let mut trait_decls: HashMap<String, LocalTrait> = HashMap::new();
let mut trait_fields = HashMap::new();
let mut prim_aliases = std::collections::HashSet::new();
let mut extern_fns = std::collections::HashSet::new();
let mut drop_types = std::collections::HashSet::new();
let mut deref_target = HashMap::new();
let mut lazy_statics = std::collections::HashSet::new();
collect_decls(items, include_tests, &mut uses, &mut fields, &mut field_elem, &mut rets,
&mut enum_tmp, &mut trait_impls, &mut trait_decls, &mut trait_fields, &mut prim_aliases,
&mut extern_fns, &mut drop_types, &mut deref_target, &mut lazy_statics);
FileDecls {
fields,
field_elem,
rets,
enum_tmp,
trait_impls,
trait_decls: trait_decls
.into_iter()
.map(|(k, v)| (k, (v.count, v.methods.into_iter().collect())))
.collect(),
trait_fields,
prim_aliases: prim_aliases.into_iter().collect(),
extern_fns: extern_fns.into_iter().collect(),
drop_types: drop_types.into_iter().collect(),
deref_target,
lazy_statics: lazy_statics.into_iter().collect(),
}
}
#[derive(Default)]
pub(crate) struct MergedDecls {
pub(crate) fields: FieldIndex,
pub(crate) field_elem: FieldElemIndex,
pub(crate) rets: HashMap<String, Option<String>>,
pub(crate) enum_tmp: HashMap<String, Option<String>>,
pub(crate) trait_impls: TraitImplIndex,
pub(crate) trait_decls: HashMap<String, LocalTrait>,
pub(crate) trait_fields: TraitFieldIndex,
pub(crate) prim_aliases: std::collections::HashSet<String>,
pub(crate) extern_fns: std::collections::HashSet<String>,
pub(crate) drop_types: std::collections::HashSet<String>,
pub(crate) deref_target: HashMap<String, String>,
pub(crate) lazy_statics: std::collections::HashSet<String>,
}
pub(crate) fn merge_decls(acc: &mut MergedDecls, fd: &FileDecls) {
for (s, fmap) in &fd.fields {
let e = acc.fields.entry(s.clone()).or_default();
for (k, v) in fmap {
e.insert(k.clone(), v.clone());
}
}
for (s, fmap) in &fd.field_elem {
let e = acc.field_elem.entry(s.clone()).or_default();
for (k, v) in fmap {
e.insert(k.clone(), v.clone());
}
}
let merge_amb = |dst: &mut HashMap<String, Option<String>>, src: &HashMap<String, Option<String>>| {
for (leaf, val) in src {
match val {
None => {
dst.insert(leaf.clone(), None); }
Some(tp) => match dst.get(leaf) {
None => {
dst.insert(leaf.clone(), Some(tp.clone()));
}
Some(Some(prev)) if prev != tp => {
dst.insert(leaf.clone(), None); }
Some(Some(_)) => {} Some(None) => {} },
}
}
};
merge_amb(&mut acc.rets, &fd.rets);
merge_amb(&mut acc.enum_tmp, &fd.enum_tmp);
for (tr, tys) in &fd.trait_impls {
acc.trait_impls.entry(tr.clone()).or_default().extend(tys.iter().cloned());
}
for (tr, (count, methods)) in &fd.trait_decls {
let e = acc.trait_decls.entry(tr.clone()).or_default();
e.count += count;
for m in methods {
e.methods.insert(m.clone());
}
}
for (s, fmap) in &fd.trait_fields {
let e = acc.trait_fields.entry(s.clone()).or_default();
for (k, v) in fmap {
e.insert(k.clone(), v.clone());
}
}
for a in &fd.prim_aliases {
acc.prim_aliases.insert(a.clone()); }
for n in &fd.extern_fns {
acc.extern_fns.insert(n.clone()); }
for n in &fd.drop_types {
acc.drop_types.insert(n.clone()); }
for (k, v) in &fd.deref_target {
acc.deref_target.insert(k.clone(), v.clone()); }
for n in &fd.lazy_statics {
acc.lazy_statics.insert(n.clone()); }
}
pub(crate) fn decl_index_digest(m: &MergedDecls) -> String {
let mut s = String::new();
let nested = |s: &mut String, tag: &str, map: &HashMap<String, HashMap<String, String>>| {
s.push_str(tag);
let mut keys: Vec<&String> = map.keys().collect();
keys.sort();
for k in keys {
s.push('|');
s.push_str(k);
let inner = &map[k];
let mut ik: Vec<&String> = inner.keys().collect();
ik.sort();
for f in ik {
s.push(';');
s.push_str(f);
s.push('=');
s.push_str(&inner[f]);
}
}
s.push('\n');
};
nested(&mut s, "fields", &m.fields);
nested(&mut s, "field_elem", &m.field_elem);
let amb = |s: &mut String, tag: &str, map: &HashMap<String, Option<String>>| {
s.push_str(tag);
let mut keys: Vec<&String> = map.keys().collect();
keys.sort();
for k in keys {
s.push('|');
s.push_str(k);
s.push('=');
s.push_str(map[k].as_deref().unwrap_or("\u{0}AMBIG"));
}
s.push('\n');
};
amb(&mut s, "rets", &m.rets);
amb(&mut s, "enum", &m.enum_tmp);
s.push_str("trait_impls");
let mut tik: Vec<&String> = m.trait_impls.keys().collect();
tik.sort();
for k in tik {
s.push('|');
s.push_str(k);
for ty in &m.trait_impls[k] {
s.push(';');
s.push_str(ty);
}
}
s.push('\n');
s.push_str("trait_decls");
let mut tdk: Vec<&String> = m.trait_decls.keys().collect();
tdk.sort();
for k in tdk {
let lt = &m.trait_decls[k];
s.push('|');
s.push_str(k);
s.push(':');
s.push_str(<.count.to_string());
let mut ms: Vec<&String> = lt.methods.iter().collect();
ms.sort();
for mname in ms {
s.push(';');
s.push_str(mname);
}
}
s.push('\n');
nested_tf(&mut s, &m.trait_fields);
s.push_str("prim_aliases");
let mut pak: Vec<&String> = m.prim_aliases.iter().collect();
pak.sort();
for a in pak {
s.push('|');
s.push_str(a);
}
s.push('\n');
s.push_str("extern_fns");
let mut efk: Vec<&String> = m.extern_fns.iter().collect();
efk.sort();
for a in efk {
s.push('|');
s.push_str(a);
}
s.push('\n');
s.push_str("drop_types");
let mut dtk: Vec<&String> = m.drop_types.iter().collect();
dtk.sort();
for a in dtk {
s.push('|');
s.push_str(a);
}
s.push('\n');
s.push_str("lazy_statics");
let mut lsk: Vec<&String> = m.lazy_statics.iter().collect();
lsk.sort();
for a in lsk {
s.push('|');
s.push_str(a);
}
s.push('\n');
s.push_str("features");
for f in active_features_sorted() {
s.push('|');
s.push_str(&f);
}
s.push('\n');
fnv1a(s.as_bytes())
}
pub(crate) fn nested_tf(s: &mut String, map: &TraitFieldIndex) {
s.push_str("trait_fields");
let mut keys: Vec<&String> = map.keys().collect();
keys.sort();
for k in keys {
s.push('|');
s.push_str(k);
let inner = &map[k];
let mut ik: Vec<&String> = inner.keys().collect();
ik.sort();
for f in ik {
s.push(';');
s.push_str(f);
s.push('=');
s.push_str(&inner[f].join(","));
}
}
s.push('\n');
}
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) struct FileCache {
pub(crate) content_hash: String,
pub(crate) decls: FileDecls,
pub(crate) decl_index_hash: String,
pub(crate) fninfos: Vec<FnInfo>,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) struct ScanCache {
pub(crate) schema: String,
pub(crate) files: HashMap<String, FileCache>,
}