use crate::graph;
use super::coverage::{tests_model_for_id, TestsResult};
use super::impact::{impact_model_for_seed, ImpactResult, SeedKind};
use super::index::GraphIndex;
use super::member::{exact_member_owner, qualified_seed, MemberCandidate};
use super::read::{build_read_model, read_result_from_refs, ReadResult};
use super::refs::{build_refs_model, member_refs_from_owners, MemberRefsOutcome, RefsResult};
use super::refs_tables::{DEFAULT_CAP, INBOUND_CAP, OUTBOUND_CAP};
#[derive(Debug, Clone, PartialEq)]
pub enum PickedSeed {
Member(MemberCandidate),
Type(String),
}
pub fn type_candidate_row(id: &str, d: &graph::Def) -> String {
format!("{id} {}:{} {}", d.file, d.line, d.kind)
}
pub fn member_candidate_row(c: &MemberCandidate) -> String {
format!("{}.{} {}:{}", c.owner, c.name, c.file, c.line)
}
pub fn type_candidates_in_refusal_order(index: &GraphIndex, ids: &[String]) -> Vec<String> {
let mut rows: Vec<(String, String)> = ids
.iter()
.map(|id| {
let d = candidate_def(index, id);
(type_candidate_row(id, d), id.clone())
})
.collect();
rows.sort_by(|a, b| a.0.cmp(&b.0));
rows.into_iter().map(|(_, id)| id).collect()
}
pub fn candidate_def<'a>(index: &'a GraphIndex, id: &str) -> &'a graph::Def {
index
.def(id)
.expect("ambiguous candidate id must resolve to a graph def")
}
pub fn pick_refs(
index: &GraphIndex,
picked: &PickedSeed,
out: bool,
cap: usize,
inbound_cap: usize,
outbound_cap: usize,
all_out: bool,
) -> RefsResult {
match picked {
PickedSeed::Type(id) => {
build_refs_model(index, id, out, cap, inbound_cap, outbound_cap, all_out)
}
PickedSeed::Member(c) => match member_refs_for_candidate(index, c, inbound_cap) {
Some(MemberRefsOutcome::Models(models)) => RefsResult::Members(models),
Some(MemberRefsOutcome::Ambiguous(candidates)) => {
RefsResult::MemberAmbiguous(candidates)
}
None => RefsResult::NotFound,
},
}
}
pub fn pick_read(index: &GraphIndex, picked: &PickedSeed) -> ReadResult {
match picked {
PickedSeed::Type(id) => build_read_model(index, id),
PickedSeed::Member(_) => {
let refs = pick_refs(
index,
picked,
false,
DEFAULT_CAP,
INBOUND_CAP,
OUTBOUND_CAP,
false,
);
read_result_from_refs(index, refs)
}
}
}
pub fn pick_tests(index: &GraphIndex, picked: &PickedSeed) -> TestsResult {
match picked {
PickedSeed::Type(id) => tests_model_for_id(index, id, id),
PickedSeed::Member(c) => match exact_member_owner(index, &c.name, &c.owner) {
Some((owner, _)) => tests_model_for_id(index, &owner, &qualified_seed(c)),
None => TestsResult::NotFound,
},
}
}
pub fn pick_impact(
index: &GraphIndex,
picked: &PickedSeed,
hops: u32,
cap: usize,
iface: bool,
iface_max_fanin: usize,
hub_max_indegree: usize,
) -> ImpactResult {
let id = match picked {
PickedSeed::Type(id) => id.clone(),
PickedSeed::Member(c) => match exact_member_owner(index, &c.name, &c.owner) {
Some((owner, _)) => owner,
None => {
return ImpactResult::NotFound {
kind: SeedKind::Symbol,
}
}
},
};
impact_model_for_seed(
index,
SeedKind::Symbol,
vec![id],
hops,
cap,
iface,
iface_max_fanin,
hub_max_indegree,
)
}
fn member_refs_for_candidate(
index: &GraphIndex,
c: &MemberCandidate,
inbound_cap: usize,
) -> Option<MemberRefsOutcome> {
let owners = exact_member_owner(index, &c.name, &c.owner)
.into_iter()
.collect::<Vec<_>>();
member_refs_from_owners(index, &qualified_seed(c), &c.name, owners, inbound_cap)
}