1use clap::ValueEnum;
5use tabled::Tabled;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Author {
10 pub name: String,
11 pub email: String,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct Trailer {
17 pub token: String,
18 pub value: String,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct CommitMeta {
27 pub author: Author,
28 pub time_seconds: i64,
29 pub trailers: Vec<Trailer>,
30}
31
32#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
36pub struct DiffStat {
37 pub insertions: u64,
38 pub deletions: u64,
39 pub files: u64,
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)]
44pub enum SortBy {
45 Author,
47 Commits,
49 Files,
51 Insertions,
53 Deletions,
55 Net,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct Options {
62 pub range: String,
64 pub email: bool,
66 pub reviews: bool,
68 pub sort: SortBy,
69 pub reverse: bool,
70 pub authors: Vec<String>,
73 pub since: Option<String>,
74 pub until: Option<String>,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Tabled)]
79pub struct Stat {
80 #[tabled(rename = "Author")]
81 pub author: String,
82 #[tabled(rename = "Commits")]
83 pub commits: u64,
84 #[tabled(rename = "Changed Files")]
85 pub num_files: u64,
86 #[tabled(rename = "Insertions", display = "display_add")]
87 pub insertions: u64,
88 #[tabled(rename = "Deletions", display = "display_del")]
89 pub deletions: u64,
90 #[tabled(rename = "Net Δ", display = "display_net")]
91 pub net: i64,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Tabled)]
96pub struct Review {
97 #[tabled(rename = "Reviewer/Tester")]
98 pub author: String,
99 #[tabled(rename = "Commits")]
100 pub commits: u64,
101}
102
103#[must_use]
108pub fn display_del(n: &u64) -> String {
109 match n {
110 0 => "0".to_string(),
111 n => format!("-{n}"),
112 }
113}
114
115#[must_use]
117pub fn display_add(n: &u64) -> String {
118 match n {
119 0 => "0".to_string(),
120 n => format!("+{n}"),
121 }
122}
123
124#[must_use]
127pub fn display_net(n: &i64) -> String {
128 if *n > 0 {
129 format!("+{n}")
130 } else {
131 format!("{n}")
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use hegel::generators;
139
140 #[hegel::test]
141 fn display_add_signs_nonzero(tc: hegel::TestCase) {
142 let n = tc.draw(generators::integers::<u64>());
143 let rendered = display_add(&n);
144 if n == 0 {
145 assert_eq!(rendered, "0");
146 } else {
147 assert_eq!(rendered, format!("+{n}"));
148 }
149 }
150
151 #[hegel::test]
152 fn display_del_signs_nonzero(tc: hegel::TestCase) {
153 let n = tc.draw(generators::integers::<u64>());
154 let rendered = display_del(&n);
155 if n == 0 {
156 assert_eq!(rendered, "0");
157 } else {
158 assert_eq!(rendered, format!("-{n}"));
159 }
160 }
161
162 #[hegel::test]
166 fn display_net_signs_and_never_panics(tc: hegel::TestCase) {
167 let n = tc.draw(generators::integers::<i64>());
168 let rendered = display_net(&n);
169 if n > 0 {
170 assert_eq!(rendered, format!("+{n}"));
171 } else {
172 assert_eq!(rendered, n.to_string());
173 }
174 }
175}