sameplace/message/significance.rs
1//! Significance level
2
3use std::fmt;
4
5use strum::EnumMessage;
6
7/// SAME message significance level
8///
9/// Usually constructed as part of an [`EventCode`](crate::EventCode).
10/// See also [`MessageHeader::event()`](crate::MessageHeader::event)
11///
12/// Three-letter SAME codes sometimes use the last letter to
13/// indicate *significance* or severity.
14///
15/// | Code | Significance |
16/// |---------|---------------------------------------------------|
17/// | `xxT` | [test](crate::SignificanceLevel::Test) |
18/// | `xxS` | [statement](crate::SignificanceLevel::Statement) |
19/// | `xxE` | [emergency](crate::SignificanceLevel::Emergency) |
20/// | `xxA` | [watch](crate::SignificanceLevel::Watch) |
21/// | `xxW` | [warning](crate::SignificanceLevel::Warning) |
22///
23/// There are many message codes which do not follow this standard—and
24/// some even contradict it. sameplace knows the correct significance
25/// code for these special cases, and the
26/// [event](crate::MessageHeader::event) API will return it.
27///
28/// Significance codes can be converted directly from or to string.
29///
30/// ```
31/// use sameplace::SignificanceLevel;
32///
33/// assert_eq!(SignificanceLevel::Watch, SignificanceLevel::from("A"));
34/// assert_eq!(SignificanceLevel::Test, SignificanceLevel::from("T"));
35///
36/// assert_eq!("Test", SignificanceLevel::Test.as_display_str());
37/// assert_eq!("Test", format!("{}", SignificanceLevel::Test));
38/// assert_eq!("T", SignificanceLevel::Test.as_code_str());
39/// assert_eq!("T", format!("{:#}", SignificanceLevel::Test));
40/// ```
41///
42/// Significance levels are `Ord`. Lower significance levels
43/// represent less urgent messages, such as tests and statements.
44/// Higher significance levels represent more important or urgent
45/// messages which may merit a "noisy" notification.
46///
47/// ```
48/// # use sameplace::SignificanceLevel;
49/// assert!(SignificanceLevel::Test < SignificanceLevel::Warning);
50/// assert!(SignificanceLevel::Watch < SignificanceLevel::Warning);
51/// ```
52///
53/// Unrecognized significance levels are quietly represented as
54/// [`SignificanceLevel::Unknown`]. Clients are encouraged to treat
55/// messages with this significance level as a Warning.
56///
57/// ```
58/// # use sameplace::SignificanceLevel;
59/// assert_eq!(SignificanceLevel::Unknown, SignificanceLevel::from(""));
60/// assert!(SignificanceLevel::Unknown >= SignificanceLevel::Warning);
61/// ```
62#[derive(
63 Clone,
64 Copy,
65 Debug,
66 PartialEq,
67 Eq,
68 PartialOrd,
69 Ord,
70 Hash,
71 strum_macros::EnumMessage,
72 strum_macros::EnumIter,
73)]
74#[repr(u8)]
75pub enum SignificanceLevel {
76 /// Test
77 ///
78 /// A message intended only for testing purposes. "This is only a test."
79 #[strum(serialize = "T", detailed_message = "Test")]
80 Test,
81
82 /// Statement
83 ///
84 /// > A message containing follow up information to a warning, watch,
85 /// > or emergency (NWSI 10-1712).
86 #[strum(serialize = "S", detailed_message = "Statement")]
87 Statement,
88
89 /// Emergency
90 ///
91 /// > An event that by itself would not kill or injure or do property
92 /// > damage, but indirectly may cause other things to happen that
93 /// > result in a hazard. Example, a major power or telephone loss in
94 /// > a large city alone is not a direct hazard but disruption to
95 /// > other critical services could create a variety of conditions
96 /// > that could directly threaten public safety (NWSI 10-1712).
97 #[strum(serialize = "E", detailed_message = "Emergency")]
98 Emergency,
99
100 /// Watch
101 ///
102 /// > Meets the classification of a warning, but either the onset time,
103 /// > probability of occurrence, or location is uncertain (NWSI 10-1712).
104 #[strum(serialize = "A", detailed_message = "Watch")]
105 Watch,
106
107 /// Warning (the most severe event)
108 ///
109 /// > Those events that alone pose a significant threat to public
110 /// > safety and/or property, probability of occurrence and location
111 /// > is high, and the onset time is relatively short (NWSI 10-1712).
112 #[strum(serialize = "W", detailed_message = "Warning")]
113 Warning,
114
115 /// Unknown significance level
116 ///
117 /// No significance level could be determined, either by knowledge of
118 /// the complete event code or by examining the last character.
119 /// Clients are strongly advised to treat unknown-significance messages
120 /// as [`SignificanceLevel::Warning`].
121 #[strum(serialize = "", detailed_message = "Warning")]
122 Unknown,
123}
124
125impl SignificanceLevel {
126 /// Parse from string
127 ///
128 /// Parses a SAME significance level from a single-character
129 /// `code` like "`T`" for [`SignificanceLevel::Test`]. If the
130 /// input does not match a significance level, returns
131 /// [`SignificanceLevel::Unknown`].
132 ///
133 /// The user is cautioned not to blindly convert the last
134 /// character of a SAME code to a `SignificanceLevel`. There
135 /// are many event codes like "`EVI`" which do not follow the
136 /// `SignificanceLevel` convention.
137 pub fn from<S>(code: S) -> Self
138 where
139 S: AsRef<str>,
140 {
141 match code.as_ref() {
142 "T" => Self::Test,
143 "S" => Self::Statement,
144 "E" => Self::Emergency,
145 "A" => Self::Watch,
146 "W" => Self::Warning,
147 _ => Self::Unknown,
148 }
149 }
150
151 /// Human-readable string representation
152 ///
153 /// Converts to a human-readable string, like "`Warning`."
154 pub fn as_display_str(&self) -> &'static str {
155 self.get_detailed_message().expect("missing definition")
156 }
157
158 /// SAME string representation
159 ///
160 /// Returns the one-character SAME code for this
161 /// `SignificanceLevel`. While this is *frequently* the last
162 /// character of the event code, there are almost as many
163 /// exceptions to this rule as there are codes which
164 /// follow it.
165 pub fn as_code_str(&self) -> &'static str {
166 self.get_serializations()[0]
167 }
168}
169
170impl std::default::Default for SignificanceLevel {
171 fn default() -> Self {
172 SignificanceLevel::Unknown
173 }
174}
175
176impl From<&str> for SignificanceLevel {
177 fn from(s: &str) -> SignificanceLevel {
178 SignificanceLevel::from(s)
179 }
180}
181
182impl AsRef<str> for SignificanceLevel {
183 fn as_ref(&self) -> &'static str {
184 self.as_code_str()
185 }
186}
187
188impl fmt::Display for SignificanceLevel {
189 /// Printable string
190 ///
191 /// * The normal form is a human-readable string like "`Statement`"
192 /// * The alternate form is a one-character string like "`S`"
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 if f.alternate() {
195 self.as_code_str().fmt(f)
196 } else {
197 self.as_display_str().fmt(f)
198 }
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use strum::IntoEnumIterator;
205
206 use super::*;
207
208 #[test]
209 fn test_str_conversion() {
210 for sig in SignificanceLevel::iter() {
211 if sig == SignificanceLevel::Unknown {
212 continue;
213 }
214
215 let inp = SignificanceLevel::from(sig.as_code_str());
216 assert_eq!(inp, sig);
217 }
218 }
219}