use std::collections::BTreeMap;
use super::lookup::Target;
const NO_TARGETS: &[Target] = &[];
const NO_MODULES: &[usize] = &[];
#[derive(Default)]
pub(super) struct Bindings {
named: BTreeMap<usize, BTreeMap<Box<str>, Box<[Target]>>>,
globs: BTreeMap<usize, Box<[usize]>>,
}
impl Bindings {
pub(super) fn named(&self, node: usize, name: &str) -> &[Target] {
self.named
.get(&node)
.and_then(|scope| scope.get(name))
.map_or(NO_TARGETS, |found| found)
}
pub(super) fn globs(&self, node: usize) -> &[usize] {
self.globs.get(&node).map_or(NO_MODULES, |found| found)
}
pub(super) fn bind(&mut self, node: usize, name: &str, targets: &[Target]) -> bool {
let scope = self.named.entry(node).or_default();
let bound = scope
.get(name)
.map(|existing| (covers(existing, targets), existing));
let merged = match bound {
Some((true, _)) => return false,
Some((false, existing)) => union(existing, targets),
None => Box::from(targets),
};
scope.insert(Box::from(name), merged);
true
}
pub(super) fn bind_glob(&mut self, node: usize, module: usize) -> bool {
let entry = self.globs.entry(node).or_default();
match entry.contains(&module) {
true => false,
false => {
*entry = entry.iter().copied().chain([module]).collect();
true
}
}
}
}
fn covers(existing: &[Target], targets: &[Target]) -> bool {
targets.iter().all(|target| existing.contains(target))
}
fn union(existing: &[Target], targets: &[Target]) -> Box<[Target]> {
let mut merged: Vec<Target> = existing.iter().chain(targets).copied().collect();
merged.sort_unstable();
merged.dedup();
merged.into_boxed_slice()
}