1use core::fmt;
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub enum ConformanceClass {
15 A,
17 B,
19 C,
21}
22
23impl ConformanceClass {
24 pub const TOKEN_A: &'static str = "gbp/class-a";
26 pub const TOKEN_B: &'static str = "gbp/class-b";
28 pub const TOKEN_C: &'static str = "gbp/class-c";
30
31 pub fn tokens(self) -> &'static [&'static str] {
34 match self {
35 Self::A => &[Self::TOKEN_A],
36 Self::B => &[Self::TOKEN_A, Self::TOKEN_B],
37 Self::C => &[Self::TOKEN_A, Self::TOKEN_B, Self::TOKEN_C],
38 }
39 }
40
41 pub fn from_tokens<'a>(tokens: impl IntoIterator<Item = &'a str>) -> Option<Self> {
44 let mut has_a = false;
45 let mut has_b = false;
46 let mut has_c = false;
47 for t in tokens {
48 match t {
49 Self::TOKEN_A => has_a = true,
50 Self::TOKEN_B => has_b = true,
51 Self::TOKEN_C => has_c = true,
52 _ => {}
53 }
54 }
55 if has_a && has_b && has_c {
56 Some(Self::C)
57 } else if has_a && has_b {
58 Some(Self::B)
59 } else if has_a {
60 Some(Self::A)
61 } else {
62 None
63 }
64 }
65}
66
67impl fmt::Display for ConformanceClass {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 f.write_str(match self {
70 Self::A => "Class A (GBP+GSP)",
71 Self::B => "Class B (GBP+GSP+GTP)",
72 Self::C => "Class C (GBP+GSP+GTP+GAP)",
73 })
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn tokens_are_cumulative() {
83 assert_eq!(ConformanceClass::A.tokens(), &["gbp/class-a"]);
84 assert_eq!(
85 ConformanceClass::B.tokens(),
86 &["gbp/class-a", "gbp/class-b"]
87 );
88 assert_eq!(
89 ConformanceClass::C.tokens(),
90 &["gbp/class-a", "gbp/class-b", "gbp/class-c"]
91 );
92 }
93
94 #[test]
95 fn from_tokens_detects_class() {
96 assert_eq!(
97 ConformanceClass::from_tokens(["gbp/class-a"]),
98 Some(ConformanceClass::A)
99 );
100 assert_eq!(
101 ConformanceClass::from_tokens(["gbp/class-a", "gbp/class-b"]),
102 Some(ConformanceClass::B)
103 );
104 assert_eq!(
105 ConformanceClass::from_tokens(["gbp/class-a", "gbp/class-b", "gbp/class-c"]),
106 Some(ConformanceClass::C)
107 );
108 assert_eq!(ConformanceClass::from_tokens(["something-else"]), None);
109 }
110
111 #[test]
112 fn class_ordering() {
113 assert!(ConformanceClass::A < ConformanceClass::B);
114 assert!(ConformanceClass::B < ConformanceClass::C);
115 }
116}