1pub struct FieldReader<'a> {
11 fields: &'a [&'a str],
12 idx: usize,
13}
14
15impl<'a> FieldReader<'a> {
16 pub fn new(fields: &'a [&'a str]) -> Self {
17 Self { fields, idx: 0 }
18 }
19
20 pub fn f32(&mut self) -> Option<f32> {
22 let val = self.fields.get(self.idx).and_then(|f| {
23 if f.is_empty() {
24 None
25 } else {
26 f.parse::<f32>().ok()
27 }
28 });
29 self.idx += 1;
30 val
31 }
32
33 pub fn f64(&mut self) -> Option<f64> {
35 let val = self.fields.get(self.idx).and_then(|f| {
36 if f.is_empty() {
37 None
38 } else {
39 f.parse::<f64>().ok()
40 }
41 });
42 self.idx += 1;
43 val
44 }
45
46 pub fn u8(&mut self) -> Option<u8> {
48 let val = self.fields.get(self.idx).and_then(|f| {
49 if f.is_empty() {
50 None
51 } else {
52 f.parse::<u8>().ok()
53 }
54 });
55 self.idx += 1;
56 val
57 }
58
59 pub fn u32(&mut self) -> Option<u32> {
61 let val = self.fields.get(self.idx).and_then(|f| {
62 if f.is_empty() {
63 None
64 } else {
65 f.parse::<u32>().ok()
66 }
67 });
68 self.idx += 1;
69 val
70 }
71
72 pub fn char(&mut self) -> Option<char> {
74 let val = self
75 .fields
76 .get(self.idx)
77 .and_then(|f| f.chars().next().filter(|_| !f.is_empty()));
78 self.idx += 1;
79 val
80 }
81
82 pub fn string(&mut self) -> Option<String> {
84 let val = self.fields.get(self.idx).and_then(|f| {
85 if f.is_empty() {
86 None
87 } else {
88 Some((*f).to_string())
89 }
90 });
91 self.idx += 1;
92 val
93 }
94
95 pub fn skip(&mut self) {
97 self.idx += 1;
98 }
99}
100
101pub struct FieldWriter {
105 fields: Vec<String>,
106}
107
108impl FieldWriter {
109 pub fn new() -> Self {
110 Self { fields: Vec::new() }
111 }
112
113 pub fn f32(&mut self, value: Option<f32>) {
115 self.fields.push(match value {
116 Some(v) => format!("{v}"),
117 None => String::new(),
118 });
119 }
120
121 pub fn f64(&mut self, value: Option<f64>) {
123 self.fields.push(match value {
124 Some(v) => format!("{v}"),
125 None => String::new(),
126 });
127 }
128
129 pub fn u8(&mut self, value: Option<u8>) {
131 self.fields.push(match value {
132 Some(v) => v.to_string(),
133 None => String::new(),
134 });
135 }
136
137 pub fn u32(&mut self, value: Option<u32>) {
139 self.fields.push(match value {
140 Some(v) => v.to_string(),
141 None => String::new(),
142 });
143 }
144
145 pub fn char(&mut self, value: Option<char>) {
147 self.fields.push(match value {
148 Some(c) => c.to_string(),
149 None => String::new(),
150 });
151 }
152
153 pub fn fixed(&mut self, c: char) {
155 self.fields.push(c.to_string());
156 }
157
158 pub fn string(&mut self, value: Option<&str>) {
160 self.fields.push(value.unwrap_or("").to_string());
161 }
162
163 pub fn finish(self) -> Vec<String> {
165 self.fields
166 }
167}
168
169impl Default for FieldWriter {
170 fn default() -> Self {
171 Self::new()
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn reader_char() {
181 let fields = &["T", "", "AB"];
182 let mut r = FieldReader::new(fields);
183 assert_eq!(r.char(), Some('T'));
184 assert_eq!(r.char(), None);
185 assert_eq!(r.char(), Some('A')); }
187
188 #[test]
189 fn reader_f32() {
190 let fields = &["270.0", "", "abc"];
191 let mut r = FieldReader::new(fields);
192 assert_eq!(r.f32(), Some(270.0));
193 assert_eq!(r.f32(), None);
194 assert_eq!(r.f32(), None); }
196
197 #[test]
198 fn reader_past_end() {
199 let fields: &[&str] = &[];
200 let mut r = FieldReader::new(fields);
201 assert_eq!(r.f32(), None);
202 assert_eq!(r.char(), None);
203 }
204
205 #[test]
206 fn reader_skip() {
207 let fields = &["10.0", "T", "20.0"];
208 let mut r = FieldReader::new(fields);
209 assert_eq!(r.f32(), Some(10.0));
210 r.skip();
211 assert_eq!(r.f32(), Some(20.0));
212 }
213
214 #[test]
215 fn reader_string() {
216 let fields = &["DEST", ""];
217 let mut r = FieldReader::new(fields);
218 assert_eq!(r.string(), Some("DEST".to_string()));
219 assert_eq!(r.string(), None);
220 }
221
222 #[test]
223 fn writer_roundtrip() {
224 let mut w = FieldWriter::new();
225 w.f32(Some(270.0));
226 w.fixed('T');
227 w.f32(None);
228 w.fixed('M');
229 let fields = w.finish();
230 assert_eq!(fields, vec!["270", "T", "", "M"]);
231 }
232}