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}