1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum Category {
9 Schema,
10 Structure,
11 Intrinsic,
12 BestPractice,
13 Resource,
14 Security,
15 Parameter,
16 Reference,
17 Deprecation,
18 General,
19}
20
21impl Category {
22 pub const fn as_str(&self) -> &'static str {
23 match self {
24 Category::Schema => "Schema",
25 Category::Structure => "Structure",
26 Category::Intrinsic => "Intrinsic Function",
27 Category::BestPractice => "Best Practice",
28 Category::Resource => "Resource",
29 Category::Security => "Security",
30 Category::Parameter => "Parameter",
31 Category::Reference => "Reference",
32 Category::Deprecation => "Deprecation",
33 Category::General => "General",
34 }
35 }
36}
37
38impl std::str::FromStr for Category {
39 type Err = String;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 match s.to_lowercase().as_str() {
43 "schema" => Ok(Category::Schema),
44 "structure" => Ok(Category::Structure),
45 "intrinsic function" => Ok(Category::Intrinsic),
46 "best practice" | "best-practice" | "best_practice" => Ok(Category::BestPractice),
47 "resource" => Ok(Category::Resource),
48 "security" => Ok(Category::Security),
49 "parameter" => Ok(Category::Parameter),
50 "reference" => Ok(Category::Reference),
51 "deprecation" => Ok(Category::Deprecation),
52 "general" => Ok(Category::General),
53 _ => Err(format!("Invalid category: {}", s)),
54 }
55 }
56}
57
58impl fmt::Display for Category {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.write_str(self.as_str())
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use std::str::FromStr;
68
69 #[test]
70 fn as_str_round_trips_through_from_str_for_all_variants() {
71 let all = [
72 Category::Schema,
73 Category::Structure,
74 Category::Intrinsic,
75 Category::BestPractice,
76 Category::Resource,
77 Category::Security,
78 Category::Parameter,
79 Category::Reference,
80 Category::Deprecation,
81 Category::General,
82 ];
83 for cat in all {
84 assert_eq!(Category::from_str(cat.as_str()).unwrap(), cat, "round-trip failed for {:?}", cat);
85 }
86 }
87
88 #[test]
89 fn from_str_parses_case_insensitively() {
90 assert_eq!(Category::from_str("SCHEMA").unwrap(), Category::Schema);
91 assert_eq!(Category::from_str("Best Practice").unwrap(), Category::BestPractice);
92 assert_eq!(Category::from_str("BEST PRACTICE").unwrap(), Category::BestPractice);
93 }
94
95 #[test]
96 fn from_str_errors_on_freeform_category_string() {
97 let err = Category::from_str("guard:test").unwrap_err();
98 assert_eq!(err, "Invalid category: guard:test");
99 }
100}