zeph_tools/
trust_level.rs1use std::fmt;
7use std::str::FromStr;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Deserialize, Serialize)]
13#[serde(rename_all = "lowercase")]
14pub enum TrustLevel {
15 Trusted,
17 Verified,
19 #[default]
21 Quarantined,
22 Blocked,
24}
25
26impl TrustLevel {
27 #[must_use]
29 pub fn severity(self) -> u8 {
30 match self {
31 Self::Trusted => 0,
32 Self::Verified => 1,
33 Self::Quarantined => 2,
34 Self::Blocked => 3,
35 }
36 }
37
38 #[must_use]
40 pub fn min_trust(self, other: Self) -> Self {
41 if self.severity() >= other.severity() {
42 self
43 } else {
44 other
45 }
46 }
47
48 #[must_use]
49 pub fn is_active(self) -> bool {
50 !matches!(self, Self::Blocked)
51 }
52}
53
54impl FromStr for TrustLevel {
55 type Err = String;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 match s {
59 "trusted" => Ok(Self::Trusted),
60 "verified" => Ok(Self::Verified),
61 "quarantined" => Ok(Self::Quarantined),
62 "blocked" => Ok(Self::Blocked),
63 other => Err(format!(
64 "unknown trust level '{other}'; expected: trusted, verified, quarantined, blocked"
65 )),
66 }
67 }
68}
69
70impl fmt::Display for TrustLevel {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 match self {
73 Self::Trusted => f.write_str("trusted"),
74 Self::Verified => f.write_str("verified"),
75 Self::Quarantined => f.write_str("quarantined"),
76 Self::Blocked => f.write_str("blocked"),
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn severity_ordering() {
87 assert!(TrustLevel::Trusted.severity() < TrustLevel::Verified.severity());
88 assert!(TrustLevel::Verified.severity() < TrustLevel::Quarantined.severity());
89 assert!(TrustLevel::Quarantined.severity() < TrustLevel::Blocked.severity());
90 }
91
92 #[test]
93 fn min_trust_picks_least_trusted() {
94 assert_eq!(
95 TrustLevel::Trusted.min_trust(TrustLevel::Quarantined),
96 TrustLevel::Quarantined
97 );
98 assert_eq!(
99 TrustLevel::Blocked.min_trust(TrustLevel::Trusted),
100 TrustLevel::Blocked
101 );
102 }
103
104 #[test]
105 fn is_active() {
106 assert!(TrustLevel::Trusted.is_active());
107 assert!(TrustLevel::Verified.is_active());
108 assert!(TrustLevel::Quarantined.is_active());
109 assert!(!TrustLevel::Blocked.is_active());
110 }
111
112 #[test]
113 fn default_is_quarantined() {
114 assert_eq!(TrustLevel::default(), TrustLevel::Quarantined);
115 }
116
117 #[test]
118 fn display() {
119 assert_eq!(TrustLevel::Trusted.to_string(), "trusted");
120 assert_eq!(TrustLevel::Blocked.to_string(), "blocked");
121 assert_eq!(TrustLevel::Quarantined.to_string(), "quarantined");
122 assert_eq!(TrustLevel::Verified.to_string(), "verified");
123 }
124
125 #[test]
126 fn serde_roundtrip() {
127 let level = TrustLevel::Quarantined;
128 let json = serde_json::to_string(&level).unwrap();
129 assert_eq!(json, "\"quarantined\"");
130 let back: TrustLevel = serde_json::from_str(&json).unwrap();
131 assert_eq!(back, level);
132 }
133
134 #[test]
135 fn serde_all_variants() {
136 let cases = [
137 (TrustLevel::Trusted, "\"trusted\""),
138 (TrustLevel::Verified, "\"verified\""),
139 (TrustLevel::Quarantined, "\"quarantined\""),
140 (TrustLevel::Blocked, "\"blocked\""),
141 ];
142 for (level, expected_json) in cases {
143 let json = serde_json::to_string(&level).unwrap();
144 assert_eq!(json, expected_json);
145 let back: TrustLevel = serde_json::from_str(&json).unwrap();
146 assert_eq!(back, level);
147 }
148 }
149
150 #[test]
151 fn min_trust_same_level_returns_self() {
152 assert_eq!(
153 TrustLevel::Verified.min_trust(TrustLevel::Verified),
154 TrustLevel::Verified
155 );
156 assert_eq!(
157 TrustLevel::Blocked.min_trust(TrustLevel::Blocked),
158 TrustLevel::Blocked
159 );
160 }
161
162 #[test]
163 fn hash_consistent() {
164 use std::collections::HashSet;
165 let mut set = HashSet::new();
166 set.insert(TrustLevel::Trusted);
167 set.insert(TrustLevel::Verified);
168 set.insert(TrustLevel::Quarantined);
169 set.insert(TrustLevel::Blocked);
170 assert_eq!(set.len(), 4);
171 set.insert(TrustLevel::Trusted);
173 assert_eq!(set.len(), 4);
174 }
175}