verbs/
git_projection_io_plan.rs1pub fn export_commits_summary(total: usize, newly: usize) -> String {
16 let already = total.saturating_sub(newly);
17 let breakdown = if total == 0 {
18 String::new()
19 } else if newly == 0 {
20 " (already in sync)".to_string()
21 } else if already == 0 {
22 format!(" ({newly} newly written)")
23 } else {
24 format!(" ({newly} newly written, {already} already in sync)")
25 };
26 format!("{total} total{breakdown}")
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct ExportedRefSummaryFact<'a> {
32 pub name: &'a str,
33 pub tip_hex: &'a str,
35}
36
37pub fn exported_refs_summary(refs: &[ExportedRefSummaryFact<'_>]) -> String {
41 let count = refs.len();
42 if refs.is_empty() {
43 return count.to_string();
44 }
45 let listing = refs
46 .iter()
47 .map(|r| {
48 let short_tip: String = r.tip_hex.chars().take(7).collect();
49 format!("{} {short_tip}", r.name)
50 })
51 .collect::<Vec<_>>()
52 .join(" · ");
53 format!("{count} {listing}")
54}
55
56pub fn short_git_tip(tip_hex: &str) -> String {
58 tip_hex.chars().take(7).collect()
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn export_commits_summary_variants() {
67 assert_eq!(export_commits_summary(0, 0), "0 total");
68 assert_eq!(export_commits_summary(5, 0), "5 total (already in sync)");
69 assert_eq!(export_commits_summary(3, 3), "3 total (3 newly written)");
70 assert_eq!(
71 export_commits_summary(5, 2),
72 "5 total (2 newly written, 3 already in sync)"
73 );
74 }
75
76 #[test]
77 fn exported_refs_summary_lists_and_empty() {
78 assert_eq!(exported_refs_summary(&[]), "0");
79 let refs = [
80 ExportedRefSummaryFact {
81 name: "main",
82 tip_hex: "af25b9d1234",
83 },
84 ExportedRefSummaryFact {
85 name: "spike-ok",
86 tip_hex: "7f1002c",
87 },
88 ];
89 assert_eq!(
90 exported_refs_summary(&refs),
91 "2 main af25b9d · spike-ok 7f1002c"
92 );
93 assert_eq!(short_git_tip("abcdef0123"), "abcdef0");
94 }
95}