Skip to main content

forge/manifest_ledger/
ranking.rs

1// #t(file: rust_alloc_in_loop) stable rank keys own report grouping values.
2// #t(file: rust_clone_in_loop) each report row is ranked against its owned grouping key.
3
4use std::collections::{BTreeMap, BTreeSet};
5
6use super::types::LedgerRow;
7
8pub(super) fn total_by(
9    rows: &[LedgerRow],
10    key: impl Fn(&LedgerRow) -> &'static str,
11) -> BTreeMap<String, usize> {
12    let mut totals = BTreeMap::new();
13
14    for row in rows {
15        *totals.entry(key(row).to_string()).or_default() += 1;
16    }
17
18    totals
19}
20
21type LedgerGroupKey = (u8, String, Vec<Box<str>>, String);
22type LedgerGroupStats = (BTreeSet<String>, usize);
23
24pub(super) fn rank_and_sort(rows: &mut [LedgerRow]) {
25    let mut groups: BTreeMap<LedgerGroupKey, LedgerGroupStats> = BTreeMap::new();
26
27    for row in rows.iter() {
28        let key = (
29            row.disposition.sort_rank(),
30            row.category.as_str().to_string(),
31            row.semantic_ids.clone(),
32            row.evidence.clone(),
33        );
34        let group = groups.entry(key).or_default();
35
36        group.0.insert(row.spec_or_item.clone());
37        group.1 += 1;
38    }
39
40    for row in rows.iter_mut() {
41        let key = (
42            row.disposition.sort_rank(),
43            row.category.as_str().to_string(),
44            row.semantic_ids.clone(),
45            row.evidence.clone(),
46        );
47
48        if let Some((specs, operations)) = groups.get(&key) {
49            row.spec_count = specs.len();
50            row.operation_count = *operations;
51        }
52    }
53
54    rows.sort_by(|left, right| {
55        left.disposition
56            .sort_rank()
57            .cmp(&right.disposition.sort_rank())
58            .then(right.spec_count.cmp(&left.spec_count))
59            .then(right.operation_count.cmp(&left.operation_count))
60            .then(left.semantic_ids.cmp(&right.semantic_ids))
61            .then(left.manifest_path.cmp(&right.manifest_path))
62            .then(left.manifest_key.cmp(&right.manifest_key))
63            .then(left.spec_or_item.cmp(&right.spec_or_item))
64    });
65}