use std::sync::Arc;
use pedant_types::{ResolutionRecord, SymbolDefinition, SymbolReference};
use crate::edge::GraphCertainty;
use crate::error::GraphBuildError;
use crate::node::GraphNodeKind;
use crate::projection::draft::{
CandidateProjection, DefinitionProjection, ReferenceProjection, SourceFragment,
};
use crate::projection::placement::{
DefinitionIdentity, DefinitionTable, PlacedSource, SourceRecords,
};
use crate::projection::validation as neutral;
use super::mapping::{self, Vocabulary};
pub(crate) struct StatedSource<'a> {
pub(crate) table: &'a DefinitionTable,
pub(crate) vocabulary: &'a Vocabulary,
pub(crate) placed: &'a PlacedSource,
pub(crate) records: &'a SourceRecords<'a>,
}
pub(crate) fn derived_projection(
stated: &StatedSource<'_>,
) -> Result<SourceFragment, GraphBuildError> {
SourceFragment::derived(
(stated.placed, stated.table),
stated.records,
(
|definition: &SymbolDefinition| definition_kind(stated.vocabulary, definition),
mapping::reference_kind,
),
)
}
fn definition_kind(
vocabulary: &Vocabulary,
definition: &SymbolDefinition,
) -> Result<GraphNodeKind, GraphBuildError> {
neutral::stated_definition_kind(vocabulary.definition(definition.kind()), definition)
}
pub(crate) fn states_current_claim(held: &SourceFragment, stated: &StatedSource<'_>) -> bool {
held.source == stated.placed.source
&& states_definitions(&held.definitions, stated)
&& states_references(&held.references, stated.table, &stated.records.references)
}
fn states_definitions(held: &[DefinitionProjection], stated: &StatedSource<'_>) -> bool {
let reported = &stated.records.definitions;
held.len() == reported.len()
&& held
.iter()
.zip(reported.iter().copied())
.all(|(projection, definition)| states_definition(projection, stated, definition))
}
fn states_definition(
held: &DefinitionProjection,
stated: &StatedSource<'_>,
reported: (u32, &SymbolDefinition),
) -> bool {
let (at, definition) = reported;
stated.table.identity(at) == Some(&held.identity)
&& held.language == definition.language()
&& stated
.vocabulary
.states_definition(&held.kind, definition.kind())
&& states_join(
held.parent.as_ref(),
stated.table,
definition.parent().map(|parent| parent.index()),
)
}
fn states_references(
held: &[ReferenceProjection],
table: &DefinitionTable,
reported: &[(&SymbolReference, &ResolutionRecord)],
) -> bool {
held.len() == reported.len()
&& held
.iter()
.zip(reported.iter().copied())
.all(|(projection, reference)| states_reference(projection, table, reference))
}
fn states_reference(
held: &ReferenceProjection,
table: &DefinitionTable,
reported: (&SymbolReference, &ResolutionRecord),
) -> bool {
let (reference, record) = reported;
let Some(kind) = mapping::reference_kind(reference.kind()) else {
return false;
};
held.language == reference.language()
&& held.kind == kind
&& *held.text == *reference.text()
&& held.span == *SymbolReference::span(reference)
&& *held.gaps == *record.gaps()
&& states_join(
held.enclosing.as_ref(),
table,
reference
.enclosing_definition()
.map(|enclosing| enclosing.index()),
)
&& states_candidates(&held.candidates, table, record)
}
fn states_join(
held: Option<&Arc<DefinitionIdentity>>,
table: &DefinitionTable,
stated: Option<u32>,
) -> bool {
match (held, stated) {
(None, None) => true,
(Some(identity), Some(at)) => table.identity(at) == Some(identity),
(None, Some(_)) | (Some(_), None) => false,
}
}
fn states_candidates(
held: &[CandidateProjection],
table: &DefinitionTable,
record: &ResolutionRecord,
) -> bool {
held.len() == record.candidates().len()
&& held
.iter()
.zip(record.candidates())
.all(|(candidate, stated)| {
candidate.certainty == GraphCertainty::of(stated.certainty())
&& table.identity(stated.definition().index()) == Some(&candidate.target)
})
}