use alloc::vec::Vec;
use crate::pass::Outcome;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct PassRun {
name: &'static str,
outcome: Outcome,
}
impl PassRun {
#[must_use]
#[inline]
pub fn name(&self) -> &'static str {
self.name
}
#[must_use]
#[inline]
pub fn outcome(&self) -> Outcome {
self.outcome
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Report {
runs: Vec<PassRun>,
iterations: usize,
converged: bool,
}
impl Report {
pub(crate) fn with_capacity(capacity: usize) -> Self {
Self {
runs: Vec::with_capacity(capacity),
iterations: 0,
converged: false,
}
}
#[inline]
pub(crate) fn record(&mut self, name: &'static str, outcome: Outcome) {
self.runs.push(PassRun { name, outcome });
}
pub(crate) fn finalize(&mut self, iterations: usize, converged: bool) {
self.iterations = iterations;
self.converged = converged;
}
#[must_use]
#[inline]
pub fn runs(&self) -> &[PassRun] {
&self.runs
}
#[must_use]
pub fn changes(&self) -> usize {
self.runs.iter().filter(|r| r.outcome.changed()).count()
}
#[must_use]
#[inline]
pub fn iterations(&self) -> usize {
self.iterations
}
#[must_use]
#[inline]
pub fn converged(&self) -> bool {
self.converged
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_empty_report_defaults() {
let report = Report::with_capacity(0);
assert!(report.runs().is_empty());
assert_eq!(report.changes(), 0);
assert_eq!(report.iterations(), 0);
assert!(!report.converged());
}
#[test]
fn test_record_appends_in_order() {
let mut report = Report::with_capacity(0);
report.record("a", Outcome::Changed);
report.record("b", Outcome::Unchanged);
let names: alloc::vec::Vec<_> = report.runs().iter().map(PassRun::name).collect();
assert_eq!(names, ["a", "b"]);
}
#[test]
fn test_changes_counts_only_changed() {
let mut report = Report::with_capacity(0);
report.record("a", Outcome::Changed);
report.record("b", Outcome::Unchanged);
report.record("c", Outcome::Changed);
assert_eq!(report.changes(), 2);
}
#[test]
fn test_finalize_sets_aggregate() {
let mut report = Report::with_capacity(0);
report.finalize(3, true);
assert_eq!(report.iterations(), 3);
assert!(report.converged());
}
#[test]
fn test_pass_run_accessors() {
let mut report = Report::with_capacity(0);
report.record("only", Outcome::Changed);
let run = report.runs()[0];
assert_eq!(run.name(), "only");
assert_eq!(run.outcome(), Outcome::Changed);
}
}