use std::collections::BTreeMap;
use std::sync::Arc;
use pedant_types::{ReferenceKind, ResolutionReport, ResolutionUnit, SymbolKind};
use super::identity::position;
pub(crate) enum BindingFault {
UnitCountMismatch {
report: u32,
snapshot: u32,
},
UnknownKey {
unit: u32,
},
}
pub(crate) fn keyed<U>(units: &[U], key: impl Fn(&U) -> Arc<str>) -> BTreeMap<Arc<str>, &U> {
units.iter().map(|unit| (key(unit), unit)).collect()
}
pub(crate) fn bind_by_key<'units, U, B>(
stated: &[ResolutionUnit],
units: &'units [U],
key: impl Fn(&U) -> Arc<str>,
bind: impl Fn(&ResolutionUnit, &'units U) -> B,
) -> Result<Box<[B]>, BindingFault> {
match stated.len() == units.len() {
false => Err(BindingFault::UnitCountMismatch {
report: position(stated.len()),
snapshot: position(units.len()),
}),
true => {
let table = keyed(units, key);
stated
.iter()
.map(|unit| bound(&table, unit, &bind))
.collect()
}
}
}
pub(crate) fn first_unsupported_definition(
report: &ResolutionReport,
emits: impl Fn(SymbolKind) -> bool,
) -> Option<(u32, SymbolKind)> {
report
.definitions()
.iter()
.find(|definition| !emits(definition.kind()))
.map(|definition| (definition.id().index(), definition.kind()))
}
pub(crate) fn first_unsupported_reference(
report: &ResolutionReport,
emits: impl Fn(ReferenceKind) -> bool,
) -> Option<(u32, ReferenceKind)> {
report
.references()
.iter()
.find(|reference| !emits(reference.kind()))
.map(|reference| (reference.id().index(), reference.kind()))
}
fn bound<'units, U, B>(
table: &BTreeMap<Arc<str>, &'units U>,
unit: &ResolutionUnit,
bind: &impl Fn(&ResolutionUnit, &'units U) -> B,
) -> Result<B, BindingFault> {
let found = table.get(unit.key()).ok_or(BindingFault::UnknownKey {
unit: unit.id().index(),
})?;
Ok(bind(unit, found))
}