1use serde::{Deserialize, Serialize};
7
8const SHORT_OID: usize = 7;
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(tag = "kind", rename_all = "snake_case")]
13pub enum ReviewSource {
14 WorkingTree,
15 Commit { oid: String },
16 Range { oldest: String, newest: String },
17}
18
19impl ReviewSource {
20 pub fn commit(oid: impl Into<String>) -> Self {
21 Self::Commit { oid: oid.into() }
22 }
23
24 pub fn range(oldest: impl Into<String>, newest: impl Into<String>) -> Self {
25 Self::Range {
26 oldest: oldest.into(),
27 newest: newest.into(),
28 }
29 }
30
31 pub fn key(&self) -> String {
35 match self {
36 Self::WorkingTree => "working".to_owned(),
37 Self::Commit { oid } => format!("commit-{oid}"),
38 Self::Range { oldest, newest } => format!("range-{oldest}-{newest}"),
39 }
40 }
41
42 pub fn label(&self) -> String {
44 match self {
45 Self::WorkingTree => "working tree".to_owned(),
46 Self::Commit { oid } => format!("commit {}", short(oid)),
47 Self::Range { oldest, newest } => {
48 format!("range {}..{}", short(oldest), short(newest))
49 }
50 }
51 }
52}
53
54fn short(oid: &str) -> &str {
55 oid.get(..SHORT_OID).unwrap_or(oid)
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn keys_are_deterministic_and_distinct_per_source() {
64 assert_eq!(ReviewSource::WorkingTree.key(), "working");
65 assert_eq!(ReviewSource::commit("abc123").key(), "commit-abc123");
66 assert_eq!(ReviewSource::range("aaa", "bbb").key(), "range-aaa-bbb");
67 }
68
69 #[test]
70 fn labels_shorten_oids() {
71 assert_eq!(ReviewSource::WorkingTree.label(), "working tree");
72 assert_eq!(
73 ReviewSource::commit("0123456789abcdef").label(),
74 "commit 0123456"
75 );
76 assert_eq!(
77 ReviewSource::range("0123456789", "fedcba9876").label(),
78 "range 0123456..fedcba9"
79 );
80 }
81
82 #[test]
83 fn short_oid_tolerates_a_short_string() {
84 assert_eq!(ReviewSource::commit("ab").label(), "commit ab");
85 }
86
87 #[test]
88 fn round_trips_through_json_as_a_tagged_descriptor() {
89 for source in [
90 ReviewSource::WorkingTree,
91 ReviewSource::commit("abc"),
92 ReviewSource::range("aaa", "bbb"),
93 ] {
94 let json = serde_json::to_string(&source).expect("serialize");
95 let back: ReviewSource = serde_json::from_str(&json).expect("deserialize");
96 assert_eq!(source, back);
97 }
98 }
99}