bom_buddy/
station.rs

1use serde::{Deserialize, Serialize};
2use std::{mem::take, str::Lines};
3
4#[derive(Debug, Serialize, Deserialize)]
5pub struct WeatherStation {
6    pub id: u32,
7    pub district_id: String,
8    pub name: String,
9    pub start: u16,
10    pub end: Option<u16>,
11    pub latitude: f64,
12    pub longitude: f64,
13    pub source: Option<String>,
14    pub state: String,
15    pub height: Option<f64>,
16    pub barometric_height: Option<f64>,
17    pub wmo_id: Option<u32>,
18}
19
20/// A textual table containing all past and present weather stations
21/// https://reg.bom.gov.au/climate/data/lists_by_element/stations.txt
22pub struct StationsTable<'a> {
23    lines: Lines<'a>,
24    widths: [usize; 12],
25}
26
27impl<'a> StationsTable<'a> {
28    pub fn new(station_list: &'a str) -> Self {
29        let mut lines = station_list.lines();
30        lines.nth(4);
31        let widths = [8, 6, 41, 8, 8, 9, 10, 15, 4, 11, 9, 6];
32        Self { lines, widths }
33    }
34}
35
36impl<'a> Iterator for StationsTable<'a> {
37    type Item = WeatherStation;
38
39    fn next(&mut self) -> Option<Self::Item> {
40        let line = self.lines.next()?;
41
42        if line.is_empty() {
43            return None;
44        }
45
46        let mut start = 0;
47        let mut columns = Vec::new();
48        for &width in self.widths.iter() {
49            let end = start + width;
50            let column = &line[start..end].trim();
51            columns.push(column.to_string());
52            start = end;
53        }
54
55        let source = take(&mut columns[7]);
56        let source = if source.starts_with('.') {
57            None
58        } else {
59            Some(source)
60        };
61
62        Some(WeatherStation {
63            id: take(&mut columns[0]).parse().unwrap(),
64            district_id: take(&mut columns[1]),
65            name: take(&mut columns[2]).to_string(),
66            start: take(&mut columns[3]).parse().unwrap(),
67            end: take(&mut columns[4]).parse().ok(),
68            latitude: take(&mut columns[5]).parse().unwrap(),
69            longitude: take(&mut columns[6]).parse().unwrap(),
70            source,
71            state: take(&mut columns[8]).to_string(),
72            height: take(&mut columns[9]).parse().ok(),
73            barometric_height: take(&mut columns[10]).parse().ok(),
74            wmo_id: take(&mut columns[11]).parse().ok(),
75        })
76    }
77}