grib_build/
lib.rs

1use std::str::{FromStr, from_utf8};
2
3pub mod cct_csv;
4pub mod grib2_codeflag_csv;
5
6pub struct CodeRange {
7    start: usize,
8    end: usize,
9}
10
11impl CodeRange {
12    pub fn size(&self) -> usize {
13        self.end - self.start + 1
14    }
15}
16
17impl FromStr for CodeRange {
18    type Err = CodeRangeParseError;
19
20    fn from_str(s: &str) -> Result<Self, Self::Err> {
21        let input = s.as_bytes();
22        let pos = 0;
23
24        fn read_number(
25            input: &[u8],
26            mut pos: usize,
27        ) -> Result<(usize, usize), CodeRangeParseError> {
28            let start = pos;
29            while pos < input.len() && input[pos].is_ascii_digit() {
30                pos += 1;
31            }
32            let number = from_utf8(&input[start..pos])
33                .unwrap()
34                .parse::<usize>()
35                .or(Err(CodeRangeParseError::NumberNotFound))?;
36            Ok((number, pos))
37        }
38
39        fn read_hyphen(input: &[u8], pos: usize) -> Result<usize, CodeRangeParseError> {
40            if input[pos] == b'-' {
41                Ok(pos + 1)
42            } else {
43                Err(CodeRangeParseError::HyphenNotFound)
44            }
45        }
46
47        let (start, pos) = read_number(input, pos)?;
48        if pos == input.len() {
49            return Ok(CodeRange { start, end: start });
50        }
51
52        let pos = read_hyphen(input, pos)?;
53        let (end, _pos) = read_number(input, pos)?;
54
55        Ok(CodeRange { start, end })
56    }
57}
58
59pub enum CodeRangeParseError {
60    NumberNotFound,
61    HyphenNotFound,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub struct CodeTable {
66    desc: String,
67    data: Vec<(String, String)>,
68}
69
70impl CodeTable {
71    fn new(desc: String) -> Self {
72        Self {
73            desc,
74            data: Vec::new(),
75        }
76    }
77
78    fn export(&self, name: &str) -> String {
79        format!(
80            "\
81/// {}
82const {}: &[& str] = &{:#?};",
83            self.desc,
84            name,
85            self.to_vec(),
86        )
87    }
88
89    fn to_vec(&self) -> Vec<String> {
90        let mut output = Vec::new();
91
92        let mut count = 0;
93        let mut empty_count = 0;
94
95        for entry in self.data.iter() {
96            let (id, string) = entry;
97            let string = match string.as_str() {
98                "Future versions" => None,
99                "Reserved" => None,
100                "Reserved for local use" => None,
101                "Reserved for other centres" => None,
102                "Missing" => None,
103                "Missing value" => None,
104                ")" => None,
105                _ => Some(string),
106            };
107
108            if let Ok(range) = id.parse::<CodeRange>() {
109                if let Some(string) = string {
110                    while empty_count > 0 {
111                        output.push(String::new());
112                        count += 1;
113                        empty_count -= 1;
114                    }
115
116                    if count != range.start {
117                        return Vec::new(); // Sparse code tables are not
118                        // supported at the moment.
119                    }
120                    if range.size() == 1 {
121                        output.push(string.to_string());
122                    } else {
123                        for _i in range.start..=range.end {
124                            output.push(string.clone());
125                        }
126                    }
127                    count += range.size();
128                } else {
129                    empty_count += range.size();
130                }
131            }
132        }
133        output
134    }
135}