zeph_common/
trust_level.rs1use std::fmt;
11use std::str::FromStr;
12
13use serde::{Deserialize, Serialize};
14
15#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Deserialize, Serialize)]
31#[serde(rename_all = "lowercase")]
32pub enum SkillTrustLevel {
33 Trusted,
35 Verified,
37 #[default]
39 Quarantined,
40 Blocked,
42}
43
44impl SkillTrustLevel {
45 #[must_use]
55 pub const fn severity(self) -> u8 {
56 match self {
57 Self::Trusted => 0,
58 Self::Verified => 1,
59 Self::Quarantined => 2,
60 Self::Blocked => 3,
61 }
62 }
63
64 #[must_use]
75 pub const fn min_trust(self, other: Self) -> Self {
76 if self.severity() >= other.severity() {
77 self
78 } else {
79 other
80 }
81 }
82
83 #[must_use]
85 pub const fn as_str(self) -> &'static str {
86 match self {
87 Self::Trusted => "trusted",
88 Self::Verified => "verified",
89 Self::Quarantined => "quarantined",
90 Self::Blocked => "blocked",
91 }
92 }
93
94 #[must_use]
105 pub const fn is_active(self) -> bool {
106 !matches!(self, Self::Blocked)
107 }
108}
109
110impl FromStr for SkillTrustLevel {
111 type Err = String;
112
113 fn from_str(s: &str) -> Result<Self, Self::Err> {
114 match s {
115 "trusted" => Ok(Self::Trusted),
116 "verified" => Ok(Self::Verified),
117 "quarantined" => Ok(Self::Quarantined),
118 "blocked" => Ok(Self::Blocked),
119 other => Err(format!(
120 "unknown trust level '{other}'; expected: trusted, verified, quarantined, blocked"
121 )),
122 }
123 }
124}
125
126impl fmt::Display for SkillTrustLevel {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 match self {
129 Self::Trusted => f.write_str("trusted"),
130 Self::Verified => f.write_str("verified"),
131 Self::Quarantined => f.write_str("quarantined"),
132 Self::Blocked => f.write_str("blocked"),
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn severity_ordering() {
143 assert!(SkillTrustLevel::Trusted.severity() < SkillTrustLevel::Verified.severity());
144 assert!(SkillTrustLevel::Verified.severity() < SkillTrustLevel::Quarantined.severity());
145 assert!(SkillTrustLevel::Quarantined.severity() < SkillTrustLevel::Blocked.severity());
146 }
147
148 #[test]
149 fn min_trust_picks_least_trusted() {
150 assert_eq!(
151 SkillTrustLevel::Trusted.min_trust(SkillTrustLevel::Quarantined),
152 SkillTrustLevel::Quarantined
153 );
154 assert_eq!(
155 SkillTrustLevel::Blocked.min_trust(SkillTrustLevel::Trusted),
156 SkillTrustLevel::Blocked
157 );
158 }
159
160 #[test]
161 fn is_active() {
162 assert!(SkillTrustLevel::Trusted.is_active());
163 assert!(SkillTrustLevel::Verified.is_active());
164 assert!(SkillTrustLevel::Quarantined.is_active());
165 assert!(!SkillTrustLevel::Blocked.is_active());
166 }
167
168 #[test]
169 fn default_is_quarantined() {
170 assert_eq!(SkillTrustLevel::default(), SkillTrustLevel::Quarantined);
171 }
172
173 #[test]
174 fn display() {
175 assert_eq!(SkillTrustLevel::Trusted.to_string(), "trusted");
176 assert_eq!(SkillTrustLevel::Blocked.to_string(), "blocked");
177 assert_eq!(SkillTrustLevel::Quarantined.to_string(), "quarantined");
178 assert_eq!(SkillTrustLevel::Verified.to_string(), "verified");
179 }
180
181 #[test]
182 fn serde_roundtrip() {
183 let level = SkillTrustLevel::Quarantined;
184 let json = serde_json::to_string(&level).unwrap();
185 assert_eq!(json, "\"quarantined\"");
186 let back: SkillTrustLevel = serde_json::from_str(&json).unwrap();
187 assert_eq!(back, level);
188 }
189
190 #[test]
191 fn min_trust_same_level_returns_self() {
192 assert_eq!(
193 SkillTrustLevel::Verified.min_trust(SkillTrustLevel::Verified),
194 SkillTrustLevel::Verified
195 );
196 }
197}