bufkit_data/
site.rs

1#[cfg(feature = "pylib")]
2use pyo3::prelude::*;
3use std::fmt::Display;
4
5mod station_num;
6pub use station_num::StationNumber;
7
8mod state_prov;
9pub use state_prov::StateProv;
10
11/// Description of a site with a sounding.
12#[cfg_attr(feature = "pylib", pyclass(module = "bufkit_data"))]
13#[derive(Clone, Debug, PartialEq, Eq, Hash)]
14pub struct SiteInfo {
15    /// Station number, this should be unique to the site. Site ids sometimes change around.
16    pub station_num: StationNumber,
17    /// A longer, more human readable name.
18    pub name: Option<String>,
19    /// Any relevant notes about the site.
20    pub notes: Option<String>,
21    /// The state or providence where this location is located. This allows querying sites by what
22    /// state or providence they are in.
23    pub state: Option<StateProv>,
24    /// Time zone information
25    pub time_zone: Option<chrono::FixedOffset>,
26}
27
28impl SiteInfo {
29    /// Return true if there is any missing data. It ignores the notes field since this is only
30    /// rarely used. Also, there is no requirement for a site to have an id.
31    pub fn incomplete(&self) -> bool {
32        self.name.is_none()
33            || self.state.is_none()
34            || self.time_zone.is_none()
35            || !self.station_num.is_valid()
36    }
37
38    /// Get description of the site without all the meta-data details.
39    pub fn description(&self) -> String {
40        let mut desc = String::new();
41
42        if let Some(ref nm) = self.name {
43            desc += nm;
44            if let Some(st) = self.state {
45                desc += ", ";
46                desc += st.as_static_str();
47            }
48
49            desc += " ";
50        }
51
52        desc += &format!("({})", self.station_num);
53
54        desc
55    }
56}
57
58impl Display for SiteInfo {
59    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
60        writeln!(
61            formatter,
62            "Site: station_num - {:6} | name - {:20} | state - {:2} | notes - {}",
63            self.station_num,
64            self.name.as_deref().unwrap_or("None"),
65            self.state.map(|s| s.as_static_str()).unwrap_or("None"),
66            self.notes.as_deref().unwrap_or("None"),
67        )
68    }
69}
70
71impl Default for SiteInfo {
72    fn default() -> Self {
73        SiteInfo {
74            station_num: StationNumber::from(0),
75            name: None,
76            notes: None,
77            state: None,
78            time_zone: None,
79        }
80    }
81}
82
83#[cfg(feature = "pylib")]
84#[cfg_attr(feature = "pylib", pymethods)]
85impl SiteInfo {
86
87    fn __repr__(&self) -> PyResult<String> {
88        Ok(self.description())
89    }
90
91    #[getter]
92    fn get_station_num(&self) -> StationNumber {
93        self.station_num
94    }
95
96    #[getter]
97    fn get_station_name(&self) -> String {
98        self.name.clone().unwrap_or_else(|| "No Name".to_owned())
99    }
100}
101
102/*--------------------------------------------------------------------------------------------------
103                                          Unit Tests
104--------------------------------------------------------------------------------------------------*/
105#[cfg(test)]
106mod unit {
107    use super::*;
108
109    #[test]
110    fn test_site_incomplete() {
111        let complete_site = SiteInfo {
112            station_num: StationNumber::from(1),
113            name: Some("tv station".to_owned()),
114            state: Some(StateProv::VI),
115            notes: Some("".to_owned()),
116            time_zone: Some(chrono::FixedOffset::west_opt(7 * 3600).unwrap()),
117        };
118
119        let incomplete_site = SiteInfo {
120            station_num: StationNumber::from(1),
121            name: Some("tv station".to_owned()),
122            state: None,
123            notes: None,
124            time_zone: None,
125        };
126
127        assert!(!complete_site.incomplete());
128        assert!(incomplete_site.incomplete());
129    }
130}