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(); }
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}