1use crate::{
2 error::Error,
3 metas::{DataKind, FieldDef, PcdMeta, Schema, TypeKind, ValueKind, ViewPoint},
4 Result,
5};
6use std::{collections::HashSet, io::prelude::*};
7
8pub fn load_meta<R: BufRead>(reader: &mut R, line_count: &mut usize) -> Result<PcdMeta> {
9 let mut get_meta_line = |expect_entry: &str| -> Result<_> {
10 loop {
11 let mut line = String::new();
12 let read_size = reader.read_line(&mut line)?;
13 *line_count += 1;
14
15 if read_size == 0 {
16 return Err(Error::new_parse_error(*line_count, "Unexpected end of file").into());
17 }
18
19 let line_stripped = match line.split('#').next() {
20 Some("") => continue,
21 Some(remaining) => remaining,
22 None => continue,
23 };
24
25 let tokens: Vec<String> = line_stripped
26 .split_ascii_whitespace()
27 .map(|s| s.to_owned())
28 .collect();
29
30 if tokens.is_empty() {
31 let desc = format!("Cannot parse empty line at line {}", *line_count + 1);
32 return Err(Error::new_parse_error(*line_count, &desc).into());
33 }
34
35 if tokens[0] != expect_entry {
36 let desc = format!(
37 "Expect {:?} entry, found {:?} at line {}",
38 expect_entry,
39 tokens[0],
40 *line_count + 1
41 );
42 return Err(Error::new_parse_error(*line_count, &desc).into());
43 }
44
45 return Ok(tokens);
46 }
47 };
48
49 let meta_version = {
50 let tokens = get_meta_line("VERSION")?;
51 if tokens.len() == 2 {
52 match tokens[1].as_str() {
53 "0.7" => String::from("0.7"),
54 ".7" => String::from("0.7"),
55 _ => {
56 let desc = format!(
57 "Unsupported version {:?}. Supported versions are: 0.7",
58 tokens[1]
59 );
60 return Err(Error::new_parse_error(*line_count, &desc).into());
61 }
62 }
63 } else {
64 return Err(
65 Error::new_parse_error(*line_count, "VERSION line is not understood").into(),
66 );
67 }
68 };
69
70 let meta_fields = {
71 let tokens = get_meta_line("FIELDS")?;
72 if tokens.len() == 1 {
73 return Err(
74 Error::new_parse_error(*line_count, "FIELDS line is not understood").into(),
75 );
76 }
77
78 let mut name_set = HashSet::new();
79 let mut field_names: Vec<String> = vec![];
80
81 for (idx, tk) in tokens[1..].iter().enumerate() {
82 let mut field = tk.clone();
83 if field == String::from("_") {
86 field = format!("unknown_field_{idx}");
87 }
88
89 if name_set.contains(&field.clone()) {
90 let desc = format!("field name {:?} is specified more than once", field);
91 return Err(Error::new_parse_error(*line_count, &desc).into());
92 }
93
94 name_set.insert(field.clone());
95 field_names.push(field.to_owned());
96 }
97
98 field_names
99 };
100
101 let meta_size = {
102 let tokens = get_meta_line("SIZE")?;
103 if tokens.len() == 1 {
104 return Err(Error::new_parse_error(*line_count, "SIZE line is not understood").into());
105 }
106
107 let mut sizes = vec![];
108 for tk in tokens[1..].iter() {
109 let size: u64 = tk.parse()?;
110 sizes.push(size);
111 }
112
113 sizes
114 };
115
116 let meta_type = {
117 let tokens = get_meta_line("TYPE")?;
118
119 if tokens.len() == 1 {
120 return Err(Error::new_parse_error(*line_count, "TYPE line is not understood").into());
121 }
122
123 let mut types = vec![];
124 for type_char in tokens[1..].iter() {
125 let type_ = match type_char.as_str() {
126 "I" => TypeKind::I,
127 "U" => TypeKind::U,
128 "F" => TypeKind::F,
129 _ => {
130 let desc = format!("Invalid type character {:?} in TYPE line", type_char);
131 return Err(Error::new_parse_error(*line_count, &desc).into());
132 }
133 };
134 types.push(type_);
135 }
136
137 types
138 };
139
140 let meta_count = {
141 let tokens = get_meta_line("COUNT")?;
142
143 if tokens.len() == 1 {
144 return Err(Error::new_parse_error(*line_count, "COUNT line is not understood").into());
145 }
146
147 let mut counts = vec![];
148 for tk in tokens[1..].iter() {
149 let count: u64 = tk.parse()?;
150 counts.push(count);
151 }
152
153 counts
154 };
155
156 let meta_width = {
157 let tokens = get_meta_line("WIDTH")?;
158
159 if tokens.len() != 2 {
160 return Err(Error::new_parse_error(*line_count, "WIDTH line is not understood").into());
161 }
162
163 let width: u64 = tokens[1].parse()?;
164 width
165 };
166
167 let meta_height = {
168 let tokens = get_meta_line("HEIGHT")?;
169 if tokens.len() != 2 {
170 return Err(
171 Error::new_parse_error(*line_count, "HEIGHT line is not understood").into(),
172 );
173 }
174
175 let height: u64 = tokens[1].parse()?;
176 height
177 };
178
179 let meta_viewpoint = {
180 let tokens = get_meta_line("VIEWPOINT")?;
181
182 if tokens.len() != 8 {
183 return Err(
184 Error::new_parse_error(*line_count, "VIEWPOINT line is not understood").into(),
185 );
186 }
187
188 let tx = tokens[1].parse()?;
189 let ty = tokens[2].parse()?;
190 let tz = tokens[3].parse()?;
191 let qw = tokens[4].parse()?;
192 let qx = tokens[5].parse()?;
193 let qy = tokens[6].parse()?;
194 let qz = tokens[7].parse()?;
195 ViewPoint {
196 tx,
197 ty,
198 tz,
199 qw,
200 qx,
201 qy,
202 qz,
203 }
204 };
205
206 let meta_points = {
207 let tokens = get_meta_line("POINTS")?;
208
209 if tokens.len() != 2 {
210 return Err(
211 Error::new_parse_error(*line_count, "POINTS line is not understood").into(),
212 );
213 }
214
215 let count: u64 = tokens[1].parse()?;
216 count
217 };
218
219 let meta_data = {
220 let tokens = get_meta_line("DATA")?;
221
222 if tokens.len() != 2 {
223 return Err(Error::new_parse_error(*line_count, "DATA line is not understood").into());
224 }
225
226 match tokens[1].as_str() {
227 "ascii" => DataKind::Ascii,
228 "binary" => DataKind::Binary,
229 _ => {
230 return Err(
231 Error::new_parse_error(*line_count, "DATA line is not understood").into(),
232 );
233 }
234 }
235 };
236
237 if meta_size.len() != meta_fields.len() {
239 return Err(
240 Error::new_parse_error(*line_count, "SIZE entry conflicts with FIELD entry").into(),
241 );
242 }
243
244 if meta_type.len() != meta_fields.len() {
245 return Err(
246 Error::new_parse_error(*line_count, "TYPE entry conflicts with FIELD entry").into(),
247 );
248 }
249
250 if meta_count.len() != meta_fields.len() {
251 return Err(
252 Error::new_parse_error(*line_count, "COUNT entry conflicts with FIELD entry").into(),
253 );
254 }
255
256 let field_defs: Result<Schema> = {
258 meta_fields
259 .iter()
260 .zip(meta_type.iter())
261 .zip(meta_size.iter())
262 .zip(meta_count.iter())
263 .map(|(((name, type_), size), &count)| {
264 let kind = match (type_, size) {
265 (TypeKind::U, 1) => ValueKind::U8,
266 (TypeKind::U, 2) => ValueKind::U16,
267 (TypeKind::U, 4) => ValueKind::U32,
268 (TypeKind::I, 1) => ValueKind::I8,
269 (TypeKind::I, 2) => ValueKind::I16,
270 (TypeKind::I, 4) => ValueKind::I32,
271 (TypeKind::F, 4) => ValueKind::F32,
272 (TypeKind::F, 8) => ValueKind::F64,
273 _ => {
274 let desc =
275 format!("Field type {:?} with size {} is not supported", type_, size);
276 return Err(Error::new_parse_error(*line_count, &desc).into());
277 }
278 };
279
280 let meta = FieldDef {
281 name: name.to_owned(),
282 kind,
283 count,
284 };
285
286 Ok(meta)
287 })
288 .collect()
289 };
290
291 let meta = PcdMeta {
292 version: meta_version,
293 field_defs: field_defs?,
294 width: meta_width,
295 height: meta_height,
296 viewpoint: meta_viewpoint,
297 num_points: meta_points,
298 data: meta_data,
299 };
300
301 Ok(meta)
302}