doris_rs/
production.rs

1use crate::error::ParsingError;
2
3/// This structure is attached to DORIS file that were named
4/// according to the standard convention.
5#[derive(Debug, Default, Clone, PartialEq)]
6pub struct ProductionAttributes {
7    /// 3 letter satellite name
8    pub satellite: String,
9
10    /// Year of production
11    pub year: u32,
12
13    /// Production Day of Year (DOY), assumed past J2000.
14    pub doy: u32,
15
16    /// True if this file was gzip compressed
17    #[cfg(feature = "flate2")]
18    #[cfg_attr(docsrs, doc(cfg(feature = "flate2")))]
19    pub gzip_compressed: bool,
20}
21
22impl std::fmt::Display for ProductionAttributes {
23    #[cfg(not(feature = "flate2"))]
24    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25        let sat_len = self.satellite.len();
26        let mut sat_name = self.satellite[..std::cmp::min(sat_len, 5)].to_string();
27
28        for _ in sat_len..5 {
29            sat_name.push('X');
30        }
31
32        write!(f, "{}{:02}{:03}", sat_name, self.year - 2000, self.doy)
33    }
34
35    #[cfg(feature = "flate2")]
36    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
37        let sat_len = self.satellite.len();
38        let mut sat_name = self.satellite[..std::cmp::min(sat_len, 5)].to_string();
39
40        for _ in sat_len..5 {
41            sat_name.push('X');
42        }
43
44        let mut extension = "".to_string();
45
46        if self.gzip_compressed {
47            extension.push_str(".gz");
48        }
49
50        write!(
51            f,
52            "{}{:02}{:03}{}",
53            sat_name,
54            self.year - 2000,
55            self.doy,
56            extension
57        )
58    }
59}
60
61impl std::str::FromStr for ProductionAttributes {
62    type Err = ParsingError;
63
64    fn from_str(filename: &str) -> Result<Self, Self::Err> {
65        let filename = filename.to_uppercase();
66
67        let name_len = filename.len();
68
69        if name_len != 10 && name_len != 13 {
70            return Err(ParsingError::NonStandardFileName);
71        }
72
73        let mut doy = 0;
74        let mut year = 2000;
75
76        let satellite = filename[..5].to_string();
77
78        if let Ok(y) = filename[5..7].parse::<u32>() {
79            year += y;
80        }
81
82        if let Ok(day) = filename[7..10].parse::<u32>() {
83            doy = day;
84        }
85
86        Ok(Self {
87            satellite,
88            year,
89            doy,
90            #[cfg(feature = "flate2")]
91            gzip_compressed: filename.ends_with(".GZ"),
92        })
93    }
94}
95
96#[cfg(test)]
97mod test {
98    use super::*;
99    use std::str::FromStr;
100
101    #[test]
102    #[cfg(feature = "flate2")]
103    fn test_prod_attributes() {
104        for (filename, sat_name, year, doy, gzip_compressed) in [
105            ("cs2rx18164", "CS2RX", 2018, 164, false),
106            ("cs2rx18164.gz", "CS2RX", 2018, 164, true),
107        ] {
108            let prod = ProductionAttributes::from_str(filename).unwrap_or_else(|e| {
109                panic!("Failed to \"{}\": {}", filename, e);
110            });
111
112            assert_eq!(prod.satellite, sat_name);
113            assert_eq!(prod.year, year);
114            assert_eq!(prod.doy, doy);
115            assert_eq!(prod.gzip_compressed, gzip_compressed);
116        }
117    }
118}