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