use crate::graph;
use super::impact::{Hit, KindLines, VisitedEntry};
use super::why::why_for_edge;
pub(super) use super::why::Why;
#[derive(Debug, Clone, Default)]
pub(super) struct WhyTrack {
pub(super) direct: Option<Why>,
pub(super) direct_amb: Option<Why>,
pub(super) heuristic: Option<Why>,
pub(super) iface: Option<Why>,
}
fn note_line_why(slot: &mut usize, why_slot: &mut Option<Why>, line: usize, why: Why) {
if line > 0 && (*slot == 0 || line < *slot) {
*slot = line;
*why_slot = Some(why);
}
}
impl Hit {
pub(super) fn note_direct(&mut self, line: usize, edge: &graph::Edge) {
let why = why_for_edge(edge);
note_line_why(
&mut self.lines.direct,
&mut self.why_track.direct,
line,
why,
);
}
pub(super) fn note_direct_amb(&mut self, line: usize, edge: &graph::Edge) {
let why = why_for_edge(edge);
note_line_why(
&mut self.lines.direct_amb,
&mut self.why_track.direct_amb,
line,
why,
);
}
pub(super) fn note_iface(&mut self, line: usize, edge: &graph::Edge) {
let why = why_for_edge(edge);
note_line_why(&mut self.lines.iface, &mut self.why_track.iface, line, why);
}
pub(super) fn note_heuristic(&mut self, line: usize, edge: &graph::Edge) {
let why = why_for_edge(edge);
note_line_why(
&mut self.lines.heuristic,
&mut self.why_track.heuristic,
line,
why,
);
}
}
fn primary_why(lines: &KindLines, track: &WhyTrack) -> Why {
if lines.ctor_di != 0 {
return Why::CtorDi;
}
if lines.direct != 0 {
return track.direct.unwrap_or(Why::UsesMemberPrecise);
}
if lines.direct_amb != 0 {
return track.direct_amb.unwrap_or(Why::UsesMemberPrecise);
}
if lines.iface != 0 {
return track.iface.unwrap_or(Why::UsesMemberPrecise);
}
track.heuristic.unwrap_or(Why::UsesMemberGuess)
}
pub(super) fn build_visited_entry(hop: u32, infra: bool, h: &Hit) -> VisitedEntry {
VisitedEntry {
hop,
via_count: h.via_count,
ambiguous_count: h.ambiguous_count,
heuristic_count: h.heuristic_count,
ext_count: h.ext_count,
symbols: h.symbols.clone().into_vec(),
iface_via: h.iface_via.clone().into_vec(),
lines: h.lines.clone(),
infra,
why: primary_why(&h.lines, &h.why_track),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn lines(ctor_di: usize, direct: usize, direct_amb: usize, iface: usize) -> KindLines {
KindLines {
ctor_di,
direct,
direct_amb,
iface,
heuristic: 0,
}
}
#[test]
fn ctor_di_alone_wins() {
let l = lines(1, 0, 0, 0);
let track = WhyTrack::default();
assert_eq!(primary_why(&l, &track), Why::CtorDi);
}
#[test]
fn direct_alone_reports_its_tracked_why() {
let l = lines(0, 1, 0, 0);
let track = WhyTrack {
direct: Some(Why::UsesType),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::UsesType);
}
#[test]
fn direct_amb_alone_reports_its_tracked_why() {
let l = lines(0, 0, 1, 0);
let track = WhyTrack {
direct_amb: Some(Why::Inherits),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::Inherits);
}
#[test]
fn iface_alone_reports_its_tracked_why() {
let l = lines(0, 0, 0, 1);
let track = WhyTrack {
iface: Some(Why::UsesMemberExt),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::UsesMemberExt);
}
#[test]
fn heuristic_alone_reports_its_tracked_why() {
let l = lines(0, 0, 0, 0);
let track = WhyTrack {
heuristic: Some(Why::UsesMemberGuess),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::UsesMemberGuess);
}
#[test]
fn ctor_di_outranks_direct() {
let l = lines(1, 1, 0, 0);
let track = WhyTrack {
direct: Some(Why::UsesType),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::CtorDi);
}
#[test]
fn direct_outranks_direct_amb() {
let l = lines(0, 1, 1, 0);
let track = WhyTrack {
direct: Some(Why::UsesType),
direct_amb: Some(Why::Inherits),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::UsesType);
}
#[test]
fn direct_amb_outranks_iface() {
let l = lines(0, 0, 1, 1);
let track = WhyTrack {
direct_amb: Some(Why::Inherits),
iface: Some(Why::UsesMemberExt),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::Inherits);
}
#[test]
fn iface_outranks_heuristic() {
let l = lines(0, 0, 0, 1);
let track = WhyTrack {
iface: Some(Why::UsesMemberExt),
heuristic: Some(Why::UsesMemberGuess),
..WhyTrack::default()
};
assert_eq!(primary_why(&l, &track), Why::UsesMemberExt);
}
#[test]
fn all_five_slots_set_still_picks_ctor_di() {
let l = KindLines {
ctor_di: 1,
direct: 1,
direct_amb: 1,
iface: 1,
heuristic: 1,
};
let track = WhyTrack {
direct: Some(Why::UsesType),
direct_amb: Some(Why::Inherits),
iface: Some(Why::UsesMemberExt),
heuristic: Some(Why::UsesMemberGuess),
};
assert_eq!(primary_why(&l, &track), Why::CtorDi);
}
}