1use std::fmt;
7use std::str::FromStr;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, thiserror::Error)]
17#[error("invalid load mode: {value:?}; expected one of: summary, operational, executable, full")]
18pub struct ParseLoadModeError {
19 pub value: String,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
31#[serde(rename_all = "snake_case")]
32pub enum LoadMode {
33 Summary,
35 Operational,
37 Executable,
39 Full,
41}
42
43impl fmt::Display for LoadMode {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Self::Summary => write!(f, "summary"),
47 Self::Operational => write!(f, "operational"),
48 Self::Executable => write!(f, "executable"),
49 Self::Full => write!(f, "full"),
50 }
51 }
52}
53
54impl FromStr for LoadMode {
55 type Err = ParseLoadModeError;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 match s {
59 "summary" => Ok(Self::Summary),
60 "operational" => Ok(Self::Operational),
61 "executable" => Ok(Self::Executable),
62 "full" => Ok(Self::Full),
63 _ => Err(ParseLoadModeError {
64 value: s.to_owned(),
65 }),
66 }
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub(crate) enum FieldCategory {
78 Summary,
79 Operational,
80 Executable,
81 Full,
82}
83
84impl FieldCategory {
85 #[must_use]
87 pub(crate) fn included_in(self, mode: LoadMode) -> bool {
88 match mode {
89 LoadMode::Summary => self == FieldCategory::Summary,
90 LoadMode::Operational => {
91 matches!(self, FieldCategory::Summary | FieldCategory::Operational)
92 }
93 LoadMode::Executable => matches!(
94 self,
95 FieldCategory::Summary | FieldCategory::Operational | FieldCategory::Executable
96 ),
97 LoadMode::Full => true,
98 }
99 }
100}
101
102#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_load_mode_from_str_valid_returns_ok() {
112 assert_eq!("summary".parse::<LoadMode>().unwrap(), LoadMode::Summary);
113 assert_eq!(
114 "operational".parse::<LoadMode>().unwrap(),
115 LoadMode::Operational
116 );
117 assert_eq!(
118 "executable".parse::<LoadMode>().unwrap(),
119 LoadMode::Executable
120 );
121 assert_eq!("full".parse::<LoadMode>().unwrap(), LoadMode::Full);
122 }
123
124 #[test]
125 fn test_load_mode_from_str_invalid_returns_error() {
126 let err = "debug".parse::<LoadMode>().unwrap_err();
127 assert!(err.value == "debug");
128 }
129
130 #[test]
131 fn test_load_mode_display_roundtrip() {
132 for mode in [
133 LoadMode::Summary,
134 LoadMode::Operational,
135 LoadMode::Executable,
136 LoadMode::Full,
137 ] {
138 let s = mode.to_string();
139 let parsed: LoadMode = s.parse().unwrap();
140 assert_eq!(parsed, mode);
141 }
142 }
143
144 #[test]
145 fn test_field_category_summary_included_only_in_summary_and_above() {
146 assert!(FieldCategory::Summary.included_in(LoadMode::Summary));
147 assert!(FieldCategory::Summary.included_in(LoadMode::Operational));
148 assert!(FieldCategory::Summary.included_in(LoadMode::Executable));
149 assert!(FieldCategory::Summary.included_in(LoadMode::Full));
150 }
151
152 #[test]
153 fn test_field_category_operational_not_in_summary() {
154 assert!(!FieldCategory::Operational.included_in(LoadMode::Summary));
155 assert!(FieldCategory::Operational.included_in(LoadMode::Operational));
156 assert!(FieldCategory::Operational.included_in(LoadMode::Executable));
157 assert!(FieldCategory::Operational.included_in(LoadMode::Full));
158 }
159
160 #[test]
161 fn test_field_category_executable_not_in_summary_or_operational() {
162 assert!(!FieldCategory::Executable.included_in(LoadMode::Summary));
163 assert!(!FieldCategory::Executable.included_in(LoadMode::Operational));
164 assert!(FieldCategory::Executable.included_in(LoadMode::Executable));
165 assert!(FieldCategory::Executable.included_in(LoadMode::Full));
166 }
167
168 #[test]
169 fn test_field_category_full_only_in_full() {
170 assert!(!FieldCategory::Full.included_in(LoadMode::Summary));
171 assert!(!FieldCategory::Full.included_in(LoadMode::Operational));
172 assert!(!FieldCategory::Full.included_in(LoadMode::Executable));
173 assert!(FieldCategory::Full.included_in(LoadMode::Full));
174 }
175
176 #[test]
177 fn test_load_mode_serde_roundtrip() {
178 let m = LoadMode::Executable;
179 let json = serde_json::to_string(&m).unwrap();
180 assert_eq!(json, "\"executable\"");
181 let back: LoadMode = serde_json::from_str(&json).unwrap();
182 assert_eq!(m, back);
183 }
184
185 #[test]
186 fn test_parse_load_mode_error_message_contains_value() {
187 let err = "bad_mode".parse::<LoadMode>().unwrap_err();
188 let msg = err.to_string();
189 assert!(msg.contains("bad_mode"));
190 }
191}