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 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 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]
94 pub fn is_active(self) -> bool {
95 !matches!(self, Self::Blocked)
96 }
97}
98
99impl FromStr for SkillTrustLevel {
100 type Err = String;
101
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
103 match s {
104 "trusted" => Ok(Self::Trusted),
105 "verified" => Ok(Self::Verified),
106 "quarantined" => Ok(Self::Quarantined),
107 "blocked" => Ok(Self::Blocked),
108 other => Err(format!(
109 "unknown trust level '{other}'; expected: trusted, verified, quarantined, blocked"
110 )),
111 }
112 }
113}
114
115impl fmt::Display for SkillTrustLevel {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self {
118 Self::Trusted => f.write_str("trusted"),
119 Self::Verified => f.write_str("verified"),
120 Self::Quarantined => f.write_str("quarantined"),
121 Self::Blocked => f.write_str("blocked"),
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn severity_ordering() {
132 assert!(SkillTrustLevel::Trusted.severity() < SkillTrustLevel::Verified.severity());
133 assert!(SkillTrustLevel::Verified.severity() < SkillTrustLevel::Quarantined.severity());
134 assert!(SkillTrustLevel::Quarantined.severity() < SkillTrustLevel::Blocked.severity());
135 }
136
137 #[test]
138 fn min_trust_picks_least_trusted() {
139 assert_eq!(
140 SkillTrustLevel::Trusted.min_trust(SkillTrustLevel::Quarantined),
141 SkillTrustLevel::Quarantined
142 );
143 assert_eq!(
144 SkillTrustLevel::Blocked.min_trust(SkillTrustLevel::Trusted),
145 SkillTrustLevel::Blocked
146 );
147 }
148
149 #[test]
150 fn is_active() {
151 assert!(SkillTrustLevel::Trusted.is_active());
152 assert!(SkillTrustLevel::Verified.is_active());
153 assert!(SkillTrustLevel::Quarantined.is_active());
154 assert!(!SkillTrustLevel::Blocked.is_active());
155 }
156
157 #[test]
158 fn default_is_quarantined() {
159 assert_eq!(SkillTrustLevel::default(), SkillTrustLevel::Quarantined);
160 }
161
162 #[test]
163 fn display() {
164 assert_eq!(SkillTrustLevel::Trusted.to_string(), "trusted");
165 assert_eq!(SkillTrustLevel::Blocked.to_string(), "blocked");
166 assert_eq!(SkillTrustLevel::Quarantined.to_string(), "quarantined");
167 assert_eq!(SkillTrustLevel::Verified.to_string(), "verified");
168 }
169
170 #[test]
171 fn serde_roundtrip() {
172 let level = SkillTrustLevel::Quarantined;
173 let json = serde_json::to_string(&level).unwrap();
174 assert_eq!(json, "\"quarantined\"");
175 let back: SkillTrustLevel = serde_json::from_str(&json).unwrap();
176 assert_eq!(back, level);
177 }
178
179 #[test]
180 fn min_trust_same_level_returns_self() {
181 assert_eq!(
182 SkillTrustLevel::Verified.min_trust(SkillTrustLevel::Verified),
183 SkillTrustLevel::Verified
184 );
185 }
186}