Skip to main content

rfham_core/
agency.rs

1//!
2//! Provides ..., a one-line description
3//!
4//! More detailed description
5//!
6//! # Examples
7//!
8//! ```rust
9//! ```
10//!
11
12use crate::{
13    CountryCode,
14    country::{country_code_uk, country_code_us},
15    error::CoreError,
16};
17use serde::{Deserialize, Serialize};
18use serde_with::{DeserializeFromStr, SerializeDisplay};
19use std::{fmt::Display, str::FromStr};
20
21// ------------------------------------------------------------------------------------------------
22// Public Macros
23// ------------------------------------------------------------------------------------------------
24
25// ------------------------------------------------------------------------------------------------
26// Public Types
27// ------------------------------------------------------------------------------------------------
28
29#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
30pub struct Agency {
31    name: String,
32    abbreviation: Option<String>,
33    kind: AgencyKind,
34    jurisdiction: Option<Jurisdiction>,
35    url: Option<String>,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, DeserializeFromStr, SerializeDisplay)]
39pub enum AgencyKind {
40    StandardsSetting,
41    Regulatory,
42    Maintaining,
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
46#[serde(untagged)]
47pub enum Jurisdiction {
48    International,
49    Just(CountryCode),
50    All(Vec<CountryCode>),
51}
52
53// ------------------------------------------------------------------------------------------------
54// Public Functions
55// ------------------------------------------------------------------------------------------------
56
57pub fn agency_itu() -> Agency {
58    Agency::new(
59        "The International Telecommunication Union",
60        AgencyKind::StandardsSetting,
61    )
62    .with_abbreviation("ITU")
63    .with_jurisdiction(Jurisdiction::International)
64    .with_url("https://www.itu.int")
65}
66
67pub fn agency_iaru() -> Agency {
68    Agency::new(
69        "The International Amateur Radio Union",
70        AgencyKind::Maintaining,
71    )
72    .with_abbreviation("IARU")
73    .with_jurisdiction(Jurisdiction::International)
74    .with_url("https://www.iaru.org")
75}
76
77pub fn agency_arrl() -> Agency {
78    Agency::new("The American Radio Relay League", AgencyKind::Maintaining)
79        .with_abbreviation("ARRL")
80        .with_jurisdiction(Jurisdiction::International)
81        .with_url("http://www.arrl.org")
82}
83
84pub fn agency_fcc() -> Agency {
85    Agency::new("Federal Communications Commission", AgencyKind::Regulatory)
86        .with_abbreviation("FCC")
87        .with_jurisdiction(Jurisdiction::Just(country_code_us()))
88        .with_url("https://www.fcc.gov")
89}
90
91pub fn agency_ofcom() -> Agency {
92    Agency::new("Ofcom", AgencyKind::Regulatory)
93        .with_jurisdiction(Jurisdiction::Just(country_code_uk()))
94        .with_url("https://www.ofcom.org.uk")
95}
96
97pub fn agency_rsgb() -> Agency {
98    Agency::new("Radio Society of Great Britain", AgencyKind::Maintaining)
99        .with_abbreviation("RSGB")
100        .with_jurisdiction(Jurisdiction::Just(country_code_uk()))
101        .with_url("https://www.rsgb.org")
102}
103
104// ------------------------------------------------------------------------------------------------
105// Private Macros
106// ------------------------------------------------------------------------------------------------
107
108// ------------------------------------------------------------------------------------------------
109// Private Types
110// ------------------------------------------------------------------------------------------------
111
112// ------------------------------------------------------------------------------------------------
113// Implementations ❯ Agency
114// ------------------------------------------------------------------------------------------------
115
116impl Display for Agency {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        if f.alternate() {
119            write!(
120                f,
121                "{}{}, {:#}{}",
122                self.name,
123                if let Some(abbreviation) = self.abbreviation.as_ref() {
124                    format!(" ({})", abbreviation)
125                } else {
126                    String::default()
127                },
128                self.kind,
129                match &self.jurisdiction {
130                    Some(Jurisdiction::International) => "international".to_string(),
131                    Some(Jurisdiction::Just(cc)) => cc.to_string(),
132                    Some(Jurisdiction::All(ccs)) => ccs
133                        .iter()
134                        .map(|c| c.as_str())
135                        .collect::<Vec<_>>()
136                        .join(", "),
137                    None => String::default(),
138                }
139            )
140        } else {
141            write!(
142                f,
143                "{}{}",
144                self.name,
145                if let Some(abbreviation) = self.abbreviation.as_ref() {
146                    format!(" ({})", abbreviation)
147                } else {
148                    String::default()
149                }
150            )
151        }
152    }
153}
154
155impl Agency {
156    pub fn new(name: &str, kind: AgencyKind) -> Self {
157        Self {
158            name: name.to_string(),
159            abbreviation: None,
160            kind,
161            jurisdiction: None,
162            url: None,
163        }
164    }
165
166    pub fn with_abbreviation(mut self, abbreviation: &str) -> Self {
167        self.abbreviation = Some(abbreviation.to_string());
168        self
169    }
170
171    pub fn with_jurisdiction(mut self, jurisdiction: Jurisdiction) -> Self {
172        self.jurisdiction = Some(jurisdiction);
173        self
174    }
175
176    pub fn with_url(mut self, url: &str) -> Self {
177        self.url = Some(url.to_string());
178        self
179    }
180
181    pub fn within_jurisdiction(&self, country: &CountryCode) -> Option<bool> {
182        self.jurisdiction.as_ref().map(|v| v.contains(country))
183    }
184
185    pub fn name(&self) -> &String {
186        &self.name
187    }
188
189    pub fn abbreviation(&self) -> Option<&String> {
190        self.abbreviation.as_ref()
191    }
192
193    pub fn kind(&self) -> AgencyKind {
194        self.kind
195    }
196
197    pub fn jurisdiction(&self) -> Option<&Jurisdiction> {
198        self.jurisdiction.as_ref()
199    }
200
201    pub fn url(&self) -> Option<&String> {
202        self.url.as_ref()
203    }
204}
205
206// ------------------------------------------------------------------------------------------------
207// Implementations ❯ AgencyKind
208// ------------------------------------------------------------------------------------------------
209
210impl Display for AgencyKind {
211    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212        write!(
213            f,
214            "{}",
215            if f.alternate() {
216                match self {
217                    Self::StandardsSetting => "Standards-Setting Agency",
218                    Self::Regulatory => "Regulatory Agency",
219                    Self::Maintaining => "Maintaining Agency",
220                }
221            } else {
222                match self {
223                    Self::StandardsSetting => "standards",
224                    Self::Regulatory => "regulatory",
225                    Self::Maintaining => "maintaining",
226                }
227            }
228        )
229    }
230}
231
232impl FromStr for AgencyKind {
233    type Err = CoreError;
234
235    fn from_str(s: &str) -> Result<Self, Self::Err> {
236        match s {
237            "standards" => Ok(Self::StandardsSetting),
238            "regulatory" => Ok(Self::Regulatory),
239            "maintaining" => Ok(Self::Maintaining),
240            _ => Err(CoreError::InvalidValueFromStr(s.to_string(), "AgencyKind")),
241        }
242    }
243}
244
245impl AgencyKind {
246    pub fn is_standards_setting(&self) -> bool {
247        matches!(self, Self::StandardsSetting)
248    }
249
250    pub fn is_regulatory(&self) -> bool {
251        matches!(self, Self::Regulatory)
252    }
253
254    pub fn is_maintaining(&self) -> bool {
255        matches!(self, Self::Maintaining)
256    }
257}
258
259// ------------------------------------------------------------------------------------------------
260// Implementations ❯ Jurisdiction
261// ------------------------------------------------------------------------------------------------
262
263impl Display for Jurisdiction {
264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265        write!(
266            f,
267            "{}",
268            match self {
269                Self::International => "international".to_string(),
270                Self::Just(cc) => cc.to_string(),
271                Self::All(ccs) => ccs
272                    .iter()
273                    .map(|c| c.as_str())
274                    .collect::<Vec<_>>()
275                    .join(", "),
276            }
277        )
278    }
279}
280
281impl FromStr for Jurisdiction {
282    type Err = CoreError;
283
284    fn from_str(s: &str) -> Result<Self, Self::Err> {
285        if s == "international" {
286            Ok(Self::International)
287        } else if s.contains(',') {
288            let list: Result<Vec<CountryCode>, CoreError> =
289                s.split(',').map(CountryCode::from_str).collect();
290            Ok(Self::All(list?))
291        } else {
292            Ok(Self::Just(CountryCode::from_str(s)?))
293        }
294    }
295}
296
297impl Jurisdiction {
298    pub fn contains(&self, country: &CountryCode) -> bool {
299        match self {
300            Jurisdiction::International => true,
301            Jurisdiction::Just(country_code) => country_code == country,
302            Jurisdiction::All(country_codes) => country_codes.contains(country),
303        }
304    }
305}
306
307// ------------------------------------------------------------------------------------------------
308// Private Functions
309// ------------------------------------------------------------------------------------------------
310
311// ------------------------------------------------------------------------------------------------
312// Sub-Modules
313// ------------------------------------------------------------------------------------------------