use crate::analysis::ClassifiedSeam;
use crate::analysis::seams::SeamGripClass;
use crate::output::agent_seam_packets::suggested_assertion_for_classified_seam;
use crate::output::path::display_path;
use std::cmp::Ordering;
pub(crate) fn top_actionable_seams(
classified: &[ClassifiedSeam],
max_seams: usize,
) -> Vec<&ClassifiedSeam> {
let mut actionable = classified
.iter()
.filter(|entry| class_rank(entry.class).is_some())
.collect::<Vec<_>>();
actionable.sort_by(|left, right| compare_ranked_seams(left, right));
actionable.truncate(max_seams);
actionable
}
pub(super) fn actionable_total(classified: &[ClassifiedSeam]) -> usize {
classified
.iter()
.filter(|entry| class_rank(entry.class).is_some())
.count()
}
fn compare_ranked_seams(left: &ClassifiedSeam, right: &ClassifiedSeam) -> Ordering {
class_rank(left.class)
.cmp(&class_rank(right.class))
.then(
bool_rank(!left.evidence.missing_discriminators.is_empty()).cmp(&bool_rank(
!right.evidence.missing_discriminators.is_empty(),
)),
)
.then(
bool_rank(!left.evidence.related_tests.is_empty())
.cmp(&bool_rank(!right.evidence.related_tests.is_empty())),
)
.then(
bool_rank(suggested_assertion_for_classified_seam(left).is_some()).cmp(&bool_rank(
suggested_assertion_for_classified_seam(right).is_some(),
)),
)
.then(display_path(left.seam.file()).cmp(&display_path(right.seam.file())))
.then(left.seam.display_line().cmp(&right.seam.display_line()))
.then(left.seam.kind().as_str().cmp(right.seam.kind().as_str()))
.then(left.seam.id().as_str().cmp(right.seam.id().as_str()))
}
fn class_rank(class: SeamGripClass) -> Option<u8> {
Some(match class {
SeamGripClass::WeaklyGripped => 0,
SeamGripClass::Ungripped => 1,
SeamGripClass::ReachableUnrevealed => 2,
SeamGripClass::ActivationUnknown
| SeamGripClass::PropagationUnknown
| SeamGripClass::ObservationUnknown
| SeamGripClass::DiscriminationUnknown => 3,
SeamGripClass::Opaque => 4,
SeamGripClass::StronglyGripped | SeamGripClass::Intentional | SeamGripClass::Suppressed => {
return None;
}
})
}
fn bool_rank(value: bool) -> u8 {
if value { 0 } else { 1 }
}