sameplace/message/
originator.rs

1//! Originator code
2
3use std::fmt;
4
5use strum::EnumMessage;
6
7/// SAME message originator code
8///
9/// See [`MessageHeader::originator()`](crate::MessageHeader::originator).
10/// Originator codes may be also parsed from the SAME
11/// [org code and callsign](Originator::from_org_and_call):
12///
13/// ```
14/// use sameplace::Originator;
15///
16/// let orig = Originator::from_org_and_call("WXR", "KLOX/NWS");
17/// assert_eq!(Originator::NationalWeatherService, orig);
18///
19/// // other originators
20/// assert_eq!(Originator::Unknown, Originator::from_org_and_call("HUH", ""));
21/// assert_eq!("CIV", Originator::CivilAuthority.as_code_str());
22/// ```
23///
24/// Originators Display a human-readable string:
25///
26/// ```
27/// # use sameplace::Originator;
28/// # let orig = Originator::from_org_and_call("WXR", "KLOX/NWS");
29/// assert_eq!("National Weather Service", orig.as_display_str());
30/// assert_eq!("National Weather Service", &format!("{}", orig));
31/// assert_eq!("WXR", orig.as_ref());
32/// assert_eq!("WXR", &format!("{:#}", orig));
33/// ```
34///
35/// The callsign is required to reliably detect the National Weather Service
36/// and/or Environment Canada:
37///
38/// ```
39/// # use sameplace::Originator;
40/// assert_eq!(Originator::EnvironmentCanada,
41///            Originator::from_org_and_call("WXR", "EC/GC/CA"));
42/// assert_eq!("WXR", Originator::EnvironmentCanada.as_code_str());
43/// ```
44#[derive(
45    Clone, Copy, Debug, PartialEq, Eq, Hash, strum_macros::EnumMessage, strum_macros::EnumString,
46)]
47pub enum Originator {
48    /// An unknown (and probably invalid) Originator code
49    ///
50    /// Per NWSI 10-172, receivers should accept any originator code.
51    #[strum(serialize = "", detailed_message = "Unknown Originator")]
52    Unknown,
53
54    /// Primary Entry Point station for national activations
55    ///
56    /// Nation-wide activations are authorized by the President of
57    /// the United States. Takes priority over all other
58    /// messages/station programming.
59    #[strum(serialize = "PEP", detailed_message = "Primary Entry Point System")]
60    PrimaryEntryPoint,
61
62    /// Civil authorities
63    #[strum(serialize = "CIV", detailed_message = "Civil authorities")]
64    CivilAuthority,
65
66    /// National Weather Service
67    #[strum(serialize = "WXR", detailed_message = "National Weather Service")]
68    NationalWeatherService,
69
70    /// Environment Canada
71    ///
72    /// In Canada, SAME is only transmitted on the Weatheradio Canada
73    /// radio network to alert weather radios. SAME signals are not
74    /// transmitted on broadcast AM/FM or cable systems.
75    ///
76    /// This enum variant will only be selected if the sending station's
77    /// callsign matches the format of Environment Canada stations.
78    #[strum(message = "WXR", detailed_message = "Environment Canada")]
79    EnvironmentCanada,
80
81    /// EAS participant (usu. broadcast station)
82    #[strum(
83        serialize = "EAS",
84        detailed_message = "Broadcast station or cable system"
85    )]
86    BroadcastStation,
87}
88
89impl Originator {
90    /// Construct from originator string and station callsign
91    pub fn from_org_and_call<S1, S2>(org: S1, call: S2) -> Self
92    where
93        S1: AsRef<str>,
94        S2: AsRef<str>,
95    {
96        let decode = str::parse(org.as_ref()).unwrap_or_default();
97        if decode == Self::NationalWeatherService && call.as_ref().starts_with("EC/") {
98            Self::EnvironmentCanada
99        } else {
100            decode
101        }
102    }
103
104    /// Human-readable string representation
105    ///
106    /// Converts to a human-readable string, like "`Civil authorities`."
107    pub fn as_display_str(&self) -> &'static str {
108        self.get_detailed_message().expect("missing definition")
109    }
110
111    /// SAME string representation
112    ///
113    /// Returns the SAME code for this `Originator`.
114    /// [`Originator::Unknown`] returns the empty string.
115    pub fn as_code_str(&self) -> &'static str {
116        self.get_message()
117            .unwrap_or_else(|| self.get_serializations()[0])
118    }
119}
120
121impl std::default::Default for Originator {
122    fn default() -> Self {
123        Self::Unknown
124    }
125}
126
127impl AsRef<str> for Originator {
128    fn as_ref(&self) -> &'static str {
129        self.as_code_str()
130    }
131}
132
133impl fmt::Display for Originator {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        if f.alternate() {
136            self.as_code_str().fmt(f)
137        } else {
138            self.as_display_str().fmt(f)
139        }
140    }
141}