1# or [PcdSerialize](crate::record::PcdSerialize)
6respectively.
7
8These traits are not intended to implemented manually.
9Please use derive macro instead. For example,
10
11"##]
12#![cfg_attr(
13 feature = "derive",
14 doc = r##"
15```rust
16use pcd_rs::{PcdDeserialize, PcdSerialize};
17
18#[derive(PcdDeserialize, PcdSerialize)]
19pub struct TimestampedPoint {
20 x: f32,
21 y: f32,
22 z: f32,
23 timestamp: u32,
24}
25```
26"##
27)]
28# allows fields with either primitive type,
32array of primitive type or [Vec](<std::vec::Vec>) of primitive type.
33
34[PcdSerialize](crate::record::PcdSerialize) allows fields with either primitive type or
35array of primitive type. The [Vec](<std::vec::Vec>) is ruled out since the length
36is not determined in compile-time.
37
38Make sure struct field names match the `FIELDS` header in PCD data.
39Otherwise it panics at runtime. You can specify the exact name in header or bypass name check
40with attributes. The name check are automatically disabled for tuple structs.
41"##]
42#![cfg_attr(
43 feature = "derive",
44 doc = r##"
45```rust
46use pcd_rs::PcdDeserialize;
47
48#[derive(PcdDeserialize)]
49pub struct TimestampedPoint {
50 x: f32,
51 y: f32,
52 z: f32,
53 #[pcd(rename = "true_name")]
54 rust_name: u32,
55 #[pcd(ignore)]
56 whatever_name: u32,
57}
58```
59"##
60)]
61use crate::{
62 error::Error,
63 metas::{FieldDef, Schema, ValueKind},
64 traits::Value,
65 Result,
66};
67use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
68use itertools::Itertools;
69use num_traits::NumCast;
70use std::io::prelude::*;
71
72pub trait PcdDeserialize: Sized {
80 fn is_dynamic() -> bool;
81 fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)>;
82 fn read_chunk<R: BufRead>(reader: &mut R, field_defs: &Schema) -> Result<Self>;
83 fn read_line<R: BufRead>(reader: &mut R, field_defs: &Schema) -> Result<Self>;
84}
85
86pub trait PcdSerialize: Sized {
94 fn is_dynamic() -> bool;
95 fn write_spec() -> Schema;
96 fn write_chunk<R: Write + Seek>(&self, writer: &mut R, spec: &Schema) -> Result<()>;
97 fn write_line<R: Write + Seek>(&self, writer: &mut R, spec: &Schema) -> Result<()>;
98}
99
100#[derive(Debug, Clone, PartialEq)]
104pub enum Field {
105 I8(Vec<i8>),
106 I16(Vec<i16>),
107 I32(Vec<i32>),
108 U8(Vec<u8>),
109 U16(Vec<u16>),
110 U32(Vec<u32>),
111 F32(Vec<f32>),
112 F64(Vec<f64>),
113}
114
115impl Field {
116 pub fn kind(&self) -> ValueKind {
117 use Field as F;
118 use ValueKind as K;
119
120 match self {
121 F::I8(_) => K::I8,
122 F::I16(_) => K::I16,
123 F::I32(_) => K::I32,
124 F::U8(_) => K::U8,
125 F::U16(_) => K::U16,
126 F::U32(_) => K::U32,
127 F::F32(_) => K::F32,
128 F::F64(_) => K::F64,
129 }
130 }
131
132 pub fn count(&self) -> usize {
133 use Field as F;
134
135 match self {
136 F::I8(values) => values.len(),
137 F::I16(values) => values.len(),
138 F::I32(values) => values.len(),
139 F::U8(values) => values.len(),
140 F::U16(values) => values.len(),
141 F::U32(values) => values.len(),
142 F::F32(values) => values.len(),
143 F::F64(values) => values.len(),
144 }
145 }
146
147 pub fn to_value<T>(&self) -> Option<T>
148 where
149 T: Value + NumCast,
150 {
151 use Field as F;
152
153 if T::KIND != self.kind() {
154 return None;
155 }
156
157 Some(match self {
158 F::I8(v) => match &**v {
159 &[t] => T::from(t)?,
160 _ => return None,
161 },
162 F::I16(v) => match &**v {
163 &[t] => T::from(t)?,
164 _ => return None,
165 },
166 F::I32(v) => match &**v {
167 &[t] => T::from(t)?,
168 _ => return None,
169 },
170 F::U8(v) => match &**v {
171 &[t] => T::from(t)?,
172 _ => return None,
173 },
174 F::U16(v) => match &**v {
175 &[t] => T::from(t)?,
176 _ => return None,
177 },
178 F::U32(v) => match &**v {
179 &[t] => T::from(t)?,
180 _ => return None,
181 },
182 F::F32(v) => match &**v {
183 &[t] => T::from(t)?,
184 _ => return None,
185 },
186 F::F64(v) => match &**v {
187 &[t] => T::from(t)?,
188 _ => return None,
189 },
190 })
191 }
192}
193
194#[derive(Debug, Clone, PartialEq)]
196pub struct DynRecord(pub Vec<Field>);
197
198impl DynRecord {
199 pub fn is_schema_consistent(&self, schema: &Schema) -> bool {
200 if self.0.len() != schema.len() {
201 return false;
202 }
203
204 self.0
205 .iter()
206 .zip(schema.iter())
207 .all(|(field, schema_field)| {
208 use Field as F;
209 use ValueKind as K;
210
211 if field.count() != schema_field.count as usize {
212 return false;
213 }
214
215 matches!(
216 (field, schema_field.kind),
217 (F::I8(_), K::I8)
218 | (F::I16(_), K::I16)
219 | (F::I32(_), K::I32)
220 | (F::U8(_), K::U8)
221 | (F::U16(_), K::U16)
222 | (F::U32(_), K::U32)
223 | (F::F32(_), K::F32)
224 | (F::F64(_), K::F64)
225 )
226 })
227 }
228
229 pub fn to_xyz<T>(&self) -> Option<[T; 3]>
230 where
231 T: Value + NumCast,
232 {
233 use Field as F;
234
235 if self.0.first()?.kind() != T::KIND {
236 return None;
237 }
238
239 Some(match &*self.0 {
240 [F::I8(xv), F::I8(yv), F::I8(zv), ..] => match (&**xv, &**yv, &**zv) {
241 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
242 _ => return None,
243 },
244 [F::I16(xv), F::I16(yv), F::I16(zv), ..] => match (&**xv, &**yv, &**zv) {
245 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
246 _ => return None,
247 },
248 [F::I32(xv), F::I32(yv), F::I32(zv), ..] => match (&**xv, &**yv, &**zv) {
249 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
250 _ => return None,
251 },
252 [F::U8(xv), F::U8(yv), F::U8(zv), ..] => match (&**xv, &**yv, &**zv) {
253 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
254 _ => return None,
255 },
256 [F::U16(xv), F::U16(yv), F::U16(zv), ..] => match (&**xv, &**yv, &**zv) {
257 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
258 _ => return None,
259 },
260 [F::U32(xv), F::U32(yv), F::U32(zv), ..] => match (&**xv, &**yv, &**zv) {
261 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
262 _ => return None,
263 },
264 [F::F32(xv), F::F32(yv), F::F32(zv), ..] => match (&**xv, &**yv, &**zv) {
265 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
266 _ => return None,
267 },
268 [F::F64(xv), F::F64(yv), F::F64(zv), ..] => match (&**xv, &**yv, &**zv) {
269 (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
270 _ => return None,
271 },
272 _ => return None,
273 })
274 }
275}
276
277impl PcdSerialize for DynRecord {
278 fn is_dynamic() -> bool {
279 true
280 }
281
282 fn write_spec() -> Schema {
283 unreachable!();
284 }
285
286 fn write_chunk<Writer>(&self, writer: &mut Writer, spec: &Schema) -> Result<()>
287 where
288 Writer: Write + Seek,
289 {
290 if !self.is_schema_consistent(spec) {
291 return Err(Error::new_writer_schema_mismatch_error(
292 Self::write_spec().fields,
293 spec.fields.to_vec(),
294 ));
295 }
296
297 for field in self.0.iter() {
298 use Field as F;
299
300 match field {
301 F::I8(values) => {
302 values
303 .iter()
304 .map(|val| Ok(writer.write_i8(*val)?))
305 .collect::<Result<Vec<_>>>()?;
306 }
307 F::I16(values) => {
308 values
309 .iter()
310 .map(|val| Ok(writer.write_i16::<LittleEndian>(*val)?))
311 .collect::<Result<Vec<_>>>()?;
312 }
313 F::I32(values) => {
314 values
315 .iter()
316 .map(|val| Ok(writer.write_i32::<LittleEndian>(*val)?))
317 .collect::<Result<Vec<_>>>()?;
318 }
319 F::U8(values) => {
320 values
321 .iter()
322 .map(|val| Ok(writer.write_u8(*val)?))
323 .collect::<Result<Vec<_>>>()?;
324 }
325 F::U16(values) => {
326 values
327 .iter()
328 .map(|val| Ok(writer.write_u16::<LittleEndian>(*val)?))
329 .collect::<Result<Vec<_>>>()?;
330 }
331 F::U32(values) => {
332 values
333 .iter()
334 .map(|val| Ok(writer.write_u32::<LittleEndian>(*val)?))
335 .collect::<Result<Vec<_>>>()?;
336 }
337 F::F32(values) => {
338 values
339 .iter()
340 .map(|val| Ok(writer.write_f32::<LittleEndian>(*val)?))
341 .collect::<Result<Vec<_>>>()?;
342 }
343 F::F64(values) => {
344 values
345 .iter()
346 .map(|val| Ok(writer.write_f64::<LittleEndian>(*val)?))
347 .collect::<Result<Vec<_>>>()?;
348 }
349 }
350 }
351
352 Ok(())
353 }
354
355 fn write_line<Writer>(&self, writer: &mut Writer, spec: &Schema) -> Result<()>
356 where
357 Writer: Write + Seek,
358 {
359 if !self.is_schema_consistent(spec) {
360 return Err(Error::new_writer_schema_mismatch_error(
361 Self::write_spec().fields,
362 spec.fields.to_vec(),
363 ));
364 }
365
366 let mut tokens = vec![];
367
368 for field in self.0.iter() {
369 use Field as F;
370
371 match field {
372 F::I8(values) => {
373 let iter = values.iter().map(|val| val.to_string());
374 tokens.extend(iter);
375 }
376 F::I16(values) => {
377 let iter = values.iter().map(|val| val.to_string());
378 tokens.extend(iter);
379 }
380 F::I32(values) => {
381 let iter = values.iter().map(|val| val.to_string());
382 tokens.extend(iter);
383 }
384 F::U8(values) => {
385 let iter = values.iter().map(|val| val.to_string());
386 tokens.extend(iter);
387 }
388 F::U16(values) => {
389 let iter = values.iter().map(|val| val.to_string());
390 tokens.extend(iter);
391 }
392 F::U32(values) => {
393 let iter = values.iter().map(|val| val.to_string());
394 tokens.extend(iter);
395 }
396 F::F32(values) => {
397 let iter = values.iter().map(|val| val.to_string());
398 tokens.extend(iter);
399 }
400 F::F64(values) => {
401 let iter = values.iter().map(|val| val.to_string());
402 tokens.extend(iter);
403 }
404 }
405 }
406
407 writeln!(writer, "{}", tokens.join(" "))?;
408
409 Ok(())
410 }
411}
412
413impl PcdDeserialize for DynRecord {
414 fn is_dynamic() -> bool {
415 true
416 }
417
418 fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
419 unreachable!();
420 }
421
422 fn read_chunk<R: BufRead>(reader: &mut R, field_defs: &Schema) -> Result<Self> {
423 use Field as F;
424 use ValueKind as K;
425
426 let fields = field_defs
427 .iter()
428 .map(|def| {
429 let FieldDef { kind, count, .. } = *def;
430
431 let counter = 0..count;
432
433 let field = match kind {
434 K::I8 => {
435 let values = counter
436 .map(|_| Ok(reader.read_i8()?))
437 .collect::<Result<Vec<_>>>()?;
438 F::I8(values)
439 }
440 K::I16 => {
441 let values = counter
442 .map(|_| Ok(reader.read_i16::<LittleEndian>()?))
443 .collect::<Result<Vec<_>>>()?;
444 F::I16(values)
445 }
446 K::I32 => {
447 let values = counter
448 .map(|_| Ok(reader.read_i32::<LittleEndian>()?))
449 .collect::<Result<Vec<_>>>()?;
450 F::I32(values)
451 }
452 K::U8 => {
453 let values = counter
454 .map(|_| Ok(reader.read_u8()?))
455 .collect::<Result<Vec<_>>>()?;
456 F::U8(values)
457 }
458 K::U16 => {
459 let values = counter
460 .map(|_| Ok(reader.read_u16::<LittleEndian>()?))
461 .collect::<Result<Vec<_>>>()?;
462 F::U16(values)
463 }
464 K::U32 => {
465 let values = counter
466 .map(|_| Ok(reader.read_u32::<LittleEndian>()?))
467 .collect::<Result<Vec<_>>>()?;
468 F::U32(values)
469 }
470 K::F32 => {
471 let values = counter
472 .map(|_| Ok(reader.read_f32::<LittleEndian>()?))
473 .collect::<Result<Vec<_>>>()?;
474 F::F32(values)
475 }
476 K::F64 => {
477 let values = counter
478 .map(|_| Ok(reader.read_f64::<LittleEndian>()?))
479 .collect::<Result<Vec<_>>>()?;
480 F::F64(values)
481 }
482 };
483
484 Ok(field)
485 })
486 .collect::<Result<Vec<_>>>()?;
487 Ok(Self(fields))
488 }
489
490 fn read_line<R: BufRead>(reader: &mut R, field_defs: &Schema) -> Result<Self> {
491 let mut line = String::new();
492 reader.read_line(&mut line)?;
493 let tokens = line.split_ascii_whitespace().collect::<Vec<_>>();
494
495 {
496 let expect = field_defs.iter().map(|def| def.count as usize).sum();
497 if tokens.len() != expect {
498 return Err(Error::new_text_token_mismatch_error(expect, tokens.len()));
499 }
500 }
501
502 let mut tokens_iter = tokens.into_iter();
503
504 let fields: Vec<Field> = field_defs
505 .iter()
506 .map(|def| -> Result<_, Error> {
507 let FieldDef { kind, count, .. } = *def;
508
509 let count = count as usize;
510
511 let field = match kind {
512 ValueKind::I8 => {
513 let values: Vec<i8> = (&mut tokens_iter)
514 .map(|token| token.parse())
515 .take(count)
516 .try_collect()?;
517 Field::I8(values)
518 }
519 ValueKind::I16 => {
520 let values: Vec<i16> = (&mut tokens_iter)
521 .map(|token| token.parse())
522 .take(count)
523 .try_collect()?;
524 Field::I16(values)
525 }
526 ValueKind::I32 => {
527 let values: Vec<i32> = (&mut tokens_iter)
528 .map(|token| token.parse())
529 .take(count)
530 .try_collect()?;
531 Field::I32(values)
532 }
533 ValueKind::U8 => {
534 let values: Vec<u8> = (&mut tokens_iter)
535 .map(|token| token.parse())
536 .take(count)
537 .try_collect()?;
538 Field::U8(values)
539 }
540 ValueKind::U16 => {
541 let values: Vec<u16> = (&mut tokens_iter)
542 .map(|token| token.parse())
543 .take(count)
544 .try_collect()?;
545 Field::U16(values)
546 }
547 ValueKind::U32 => {
548 let values: Vec<u32> = (&mut tokens_iter)
549 .map(|token| token.parse())
550 .take(count)
551 .try_collect()?;
552 Field::U32(values)
553 }
554 ValueKind::F32 => {
555 let values: Vec<f32> = (&mut tokens_iter)
556 .map(|token| token.parse())
557 .take(count)
558 .try_collect()?;
559 Field::F32(values)
560 }
561 ValueKind::F64 => {
562 let values: Vec<f64> = (&mut tokens_iter)
563 .map(|token| token.parse())
564 .take(count)
565 .try_collect()?;
566 Field::F64(values)
567 }
568 };
569
570 Ok(field)
571 })
572 .try_collect()?;
573
574 Ok(Self(fields))
575 }
576}
577
578impl PcdDeserialize for u8 {
581 fn is_dynamic() -> bool {
582 false
583 }
584
585 fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
586 vec![(None, ValueKind::U8, Some(1))]
587 }
588
589 fn read_chunk<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
590 let value = reader.read_u8()?;
591 Ok(value)
592 }
593
594 fn read_line<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
595 let mut line = String::new();
596 reader.read_line(&mut line)?;
597 Ok(line.parse()?)
598 }
599}
600
601impl PcdDeserialize for i8 {
602 fn is_dynamic() -> bool {
603 false
604 }
605
606 fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
607 vec![(None, ValueKind::I8, Some(1))]
608 }
609
610 fn read_chunk<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
611 let value = reader.read_i8()?;
612 Ok(value)
613 }
614
615 fn read_line<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
616 let mut line = String::new();
617 reader.read_line(&mut line)?;
618 Ok(line.parse()?)
619 }
620}
621
622macro_rules! impl_primitive {
623 ($ty:ty, $kind:ident, $read:ident) => {
624 impl PcdDeserialize for $ty {
625 fn is_dynamic() -> bool {
626 false
627 }
628
629 fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
630 vec![(None, ValueKind::$kind, Some(1))]
631 }
632
633 fn read_chunk<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
634 let value = reader.$read::<LittleEndian>()?;
635 Ok(value)
636 }
637
638 fn read_line<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
639 let mut line = String::new();
640 reader.read_line(&mut line)?;
641 Ok(line.parse()?)
642 }
643 }
644 };
645}
646
647impl_primitive!(u16, U16, read_u16);
648impl_primitive!(u32, U32, read_u32);
649impl_primitive!(i16, I16, read_i16);
650impl_primitive!(i32, I32, read_i32);
651impl_primitive!(f32, F32, read_f32);
652impl_primitive!(f64, F64, read_f64);