use std::collections::BTreeMap;
use std::sync::Arc;
use pedant_types::{ResolutionReport, SourceSpan, SymbolDefinition, SymbolKind};
use crate::error::GraphBuildError;
use crate::id::index_of;
use super::fragment::SourceSet;
use super::validation;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct SourceIdentity {
unit: Arc<str>,
path: Arc<str>,
}
impl SourceIdentity {
pub(crate) fn new(unit: Arc<str>, path: Arc<str>) -> Self {
Self { unit, path }
}
pub(crate) fn shared(&self) -> Self {
Self {
unit: Arc::clone(&self.unit),
path: Arc::clone(&self.path),
}
}
pub(crate) fn path(&self) -> &Arc<str> {
&self.path
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct DefinitionIdentity {
source: SourceIdentity,
span: SourceSpan,
kind: SymbolKind,
name: Arc<str>,
occurrence: u32,
}
impl DefinitionIdentity {
fn stated(source: SourceIdentity, definition: &SymbolDefinition) -> Self {
Self {
source,
span: SymbolDefinition::span(definition).clone(),
kind: definition.kind(),
name: Arc::from(definition.name()),
occurrence: 0,
}
}
fn at(&self, occurrence: u32) -> Self {
Self {
source: self.source.shared(),
span: self.span.clone(),
kind: self.kind,
name: Arc::clone(&self.name),
occurrence,
}
}
pub(crate) fn source(&self) -> &SourceIdentity {
&self.source
}
pub(crate) fn span(&self) -> &SourceSpan {
&self.span
}
pub(crate) fn name(&self) -> &Arc<str> {
&self.name
}
}
struct PlacedDefinition {
fragment: u32,
identity: Arc<DefinitionIdentity>,
}
pub(crate) struct DefinitionTable {
placed: Box<[PlacedDefinition]>,
}
impl DefinitionTable {
pub(crate) fn new(
report: &ResolutionReport,
sources: &SourceSet,
) -> Result<Self, GraphBuildError> {
let mut occurrences: BTreeMap<DefinitionIdentity, u32> = BTreeMap::new();
let mut placed = Vec::with_capacity(report.definitions().len());
for definition in report.definitions() {
let reported = definition.unit().index();
let file = SymbolDefinition::span(definition).file();
let (fragment, source) = validation::instantiated_source(sources, reported, file)?;
let stated = DefinitionIdentity::stated(source.shared(), definition);
let occurrence = occurrences.get(&stated).copied().unwrap_or_default();
placed.push(PlacedDefinition {
fragment,
identity: Arc::new(stated.at(occurrence)),
});
occurrences.insert(stated, occurrence.saturating_add(1));
}
Ok(Self {
placed: placed.into_boxed_slice(),
})
}
pub(crate) fn identity(&self, definition: u32) -> Option<&Arc<DefinitionIdentity>> {
self.placed
.get(index_of(definition))
.map(|placed| &placed.identity)
}
pub(crate) fn fragment(&self, definition: u32) -> Option<u32> {
self.placed
.get(index_of(definition))
.map(|placed| placed.fragment)
}
}