Skip to main content

pcd_rs/
record.rs

1#![doc = r##"
2Defines serializing and deserializing traits and common record types.
3
4Any object scanned by readers or written by writers must implement
5[PcdDeserialize](crate::record::PcdDeserialize) 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#![doc = r##"
29The derive macro accepts normal structs and tuple structs, but does not accept unit structs.
30
31[PcdDeserialize](crate::record::PcdDeserialize) 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
72/// [PcdDeserialize](crate::record::PcdDeserialize) is analogous to a _point_ returned from a reader.
73///
74/// The trait is not intended to be implemented from scratch. You must
75/// derive the implementation with `#[derive(PcdDeserialize)]`.
76///
77/// When the PCD data is in Ascii mode, the record is represented by a line of literals.
78/// Otherwise if the data is in binary mode, the record is represented by a fixed size chunk.
79pub 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
86/// [PcdSerialize](crate::record::PcdSerialize) is analogous to a _point_ written by a writer.
87///
88/// The trait is not intended to be implemented from scratch. You must
89/// derive the implementation with `#[derive(PcdSerialize)]`.
90///
91/// When the PCD data is in Ascii mode, the record is represented by a line of literals.
92/// Otherwise if the data is in binary mode, the record is represented by a fixed size chunk.
93pub 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// Runtime record types
101
102/// An enum representation of untyped data fields.
103#[derive(Debug, Clone, PartialEq)]
104pub enum Field {
105    I8(Vec<i8>),
106    I16(Vec<i16>),
107    I32(Vec<i32>),
108    I64(Vec<i64>),
109    U8(Vec<u8>),
110    U16(Vec<u16>),
111    U32(Vec<u32>),
112    U64(Vec<u64>),
113    F32(Vec<f32>),
114    F64(Vec<f64>),
115}
116
117impl Field {
118    pub fn kind(&self) -> ValueKind {
119        use Field as F;
120        use ValueKind as K;
121
122        match self {
123            F::I8(_) => K::I8,
124            F::I16(_) => K::I16,
125            F::I32(_) => K::I32,
126            F::I64(_) => K::I64,
127            F::U8(_) => K::U8,
128            F::U16(_) => K::U16,
129            F::U32(_) => K::U32,
130            F::U64(_) => K::U64,
131            F::F32(_) => K::F32,
132            F::F64(_) => K::F64,
133        }
134    }
135
136    pub fn count(&self) -> usize {
137        use Field as F;
138
139        match self {
140            F::I8(values) => values.len(),
141            F::I16(values) => values.len(),
142            F::I32(values) => values.len(),
143            F::I64(values) => values.len(),
144            F::U8(values) => values.len(),
145            F::U16(values) => values.len(),
146            F::U32(values) => values.len(),
147            F::U64(values) => values.len(),
148            F::F32(values) => values.len(),
149            F::F64(values) => values.len(),
150        }
151    }
152
153    pub fn to_value<T>(&self) -> Option<T>
154    where
155        T: Value + NumCast,
156    {
157        use Field as F;
158
159        if T::KIND != self.kind() {
160            return None;
161        }
162
163        Some(match self {
164            F::I8(v) => match &**v {
165                &[t] => T::from(t)?,
166                _ => return None,
167            },
168            F::I16(v) => match &**v {
169                &[t] => T::from(t)?,
170                _ => return None,
171            },
172            F::I32(v) => match &**v {
173                &[t] => T::from(t)?,
174                _ => return None,
175            },
176            F::I64(v) => match &**v {
177                &[t] => T::from(t)?,
178                _ => return None,
179            },
180            F::U8(v) => match &**v {
181                &[t] => T::from(t)?,
182                _ => return None,
183            },
184            F::U16(v) => match &**v {
185                &[t] => T::from(t)?,
186                _ => return None,
187            },
188            F::U32(v) => match &**v {
189                &[t] => T::from(t)?,
190                _ => return None,
191            },
192            F::U64(v) => match &**v {
193                &[t] => T::from(t)?,
194                _ => return None,
195            },
196            F::F32(v) => match &**v {
197                &[t] => T::from(t)?,
198                _ => return None,
199            },
200            F::F64(v) => match &**v {
201                &[t] => T::from(t)?,
202                _ => return None,
203            },
204        })
205    }
206}
207
208/// Represents an untyped _point_ in PCD data.
209#[derive(Debug, Clone, PartialEq)]
210pub struct DynRecord(pub Vec<Field>);
211
212impl DynRecord {
213    pub fn is_schema_consistent(&self, schema: &Schema) -> bool {
214        if self.0.len() != schema.len() {
215            return false;
216        }
217
218        self.0
219            .iter()
220            .zip(schema.iter())
221            .all(|(field, schema_field)| {
222                use Field as F;
223                use ValueKind as K;
224
225                if field.count() != schema_field.count as usize {
226                    return false;
227                }
228
229                matches!(
230                    (field, schema_field.kind),
231                    (F::I8(_), K::I8)
232                        | (F::I16(_), K::I16)
233                        | (F::I32(_), K::I32)
234                        | (F::I64(_), K::I64)
235                        | (F::U8(_), K::U8)
236                        | (F::U16(_), K::U16)
237                        | (F::U32(_), K::U32)
238                        | (F::U64(_), K::U64)
239                        | (F::F32(_), K::F32)
240                        | (F::F64(_), K::F64)
241                )
242            })
243    }
244
245    pub fn to_xyz<T>(&self) -> Option<[T; 3]>
246    where
247        T: Value + NumCast,
248    {
249        use Field as F;
250
251        if self.0.first()?.kind() != T::KIND {
252            return None;
253        }
254
255        Some(match &*self.0 {
256            [F::I8(xv), F::I8(yv), F::I8(zv), ..] => match (&**xv, &**yv, &**zv) {
257                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
258                _ => return None,
259            },
260            [F::I16(xv), F::I16(yv), F::I16(zv), ..] => match (&**xv, &**yv, &**zv) {
261                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
262                _ => return None,
263            },
264            [F::I32(xv), F::I32(yv), F::I32(zv), ..] => match (&**xv, &**yv, &**zv) {
265                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
266                _ => return None,
267            },
268            [F::I64(xv), F::I64(yv), F::I64(zv), ..] => match (&**xv, &**yv, &**zv) {
269                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
270                _ => return None,
271            },
272            [F::U8(xv), F::U8(yv), F::U8(zv), ..] => match (&**xv, &**yv, &**zv) {
273                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
274                _ => return None,
275            },
276            [F::U16(xv), F::U16(yv), F::U16(zv), ..] => match (&**xv, &**yv, &**zv) {
277                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
278                _ => return None,
279            },
280            [F::U32(xv), F::U32(yv), F::U32(zv), ..] => match (&**xv, &**yv, &**zv) {
281                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
282                _ => return None,
283            },
284            [F::U64(xv), F::U64(yv), F::U64(zv), ..] => match (&**xv, &**yv, &**zv) {
285                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
286                _ => return None,
287            },
288            [F::F32(xv), F::F32(yv), F::F32(zv), ..] => match (&**xv, &**yv, &**zv) {
289                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
290                _ => return None,
291            },
292            [F::F64(xv), F::F64(yv), F::F64(zv), ..] => match (&**xv, &**yv, &**zv) {
293                (&[x], &[y], &[z]) => [T::from(x)?, T::from(y)?, T::from(z)?],
294                _ => return None,
295            },
296            _ => return None,
297        })
298    }
299}
300
301impl PcdSerialize for DynRecord {
302    fn is_dynamic() -> bool {
303        true
304    }
305
306    fn write_spec() -> Schema {
307        unreachable!();
308    }
309
310    fn write_chunk<Writer>(&self, writer: &mut Writer, spec: &Schema) -> Result<()>
311    where
312        Writer: Write + Seek,
313    {
314        if !self.is_schema_consistent(spec) {
315            return Err(Error::new_writer_schema_mismatch_error(
316                Self::write_spec().fields,
317                spec.fields.to_vec(),
318            ));
319        }
320
321        for field in self.0.iter() {
322            use Field as F;
323
324            match field {
325                F::I8(values) => {
326                    values
327                        .iter()
328                        .map(|val| Ok(writer.write_i8(*val)?))
329                        .collect::<Result<Vec<_>>>()?;
330                }
331                F::I16(values) => {
332                    values
333                        .iter()
334                        .map(|val| Ok(writer.write_i16::<LittleEndian>(*val)?))
335                        .collect::<Result<Vec<_>>>()?;
336                }
337                F::I32(values) => {
338                    values
339                        .iter()
340                        .map(|val| Ok(writer.write_i32::<LittleEndian>(*val)?))
341                        .collect::<Result<Vec<_>>>()?;
342                }
343                F::I64(values) => {
344                    values
345                        .iter()
346                        .map(|val| Ok(writer.write_i64::<LittleEndian>(*val)?))
347                        .collect::<Result<Vec<_>>>()?;
348                }
349                F::U8(values) => {
350                    values
351                        .iter()
352                        .map(|val| Ok(writer.write_u8(*val)?))
353                        .collect::<Result<Vec<_>>>()?;
354                }
355                F::U16(values) => {
356                    values
357                        .iter()
358                        .map(|val| Ok(writer.write_u16::<LittleEndian>(*val)?))
359                        .collect::<Result<Vec<_>>>()?;
360                }
361                F::U32(values) => {
362                    values
363                        .iter()
364                        .map(|val| Ok(writer.write_u32::<LittleEndian>(*val)?))
365                        .collect::<Result<Vec<_>>>()?;
366                }
367                F::U64(values) => {
368                    values
369                        .iter()
370                        .map(|val| Ok(writer.write_u64::<LittleEndian>(*val)?))
371                        .collect::<Result<Vec<_>>>()?;
372                }
373                F::F32(values) => {
374                    values
375                        .iter()
376                        .map(|val| Ok(writer.write_f32::<LittleEndian>(*val)?))
377                        .collect::<Result<Vec<_>>>()?;
378                }
379                F::F64(values) => {
380                    values
381                        .iter()
382                        .map(|val| Ok(writer.write_f64::<LittleEndian>(*val)?))
383                        .collect::<Result<Vec<_>>>()?;
384                }
385            }
386        }
387
388        Ok(())
389    }
390
391    fn write_line<Writer>(&self, writer: &mut Writer, spec: &Schema) -> Result<()>
392    where
393        Writer: Write + Seek,
394    {
395        if !self.is_schema_consistent(spec) {
396            return Err(Error::new_writer_schema_mismatch_error(
397                Self::write_spec().fields,
398                spec.fields.to_vec(),
399            ));
400        }
401
402        let mut tokens = vec![];
403
404        for field in self.0.iter() {
405            use Field as F;
406
407            match field {
408                F::I8(values) => {
409                    let iter = values.iter().map(|val| val.to_string());
410                    tokens.extend(iter);
411                }
412                F::I16(values) => {
413                    let iter = values.iter().map(|val| val.to_string());
414                    tokens.extend(iter);
415                }
416                F::I32(values) => {
417                    let iter = values.iter().map(|val| val.to_string());
418                    tokens.extend(iter);
419                }
420                F::I64(values) => {
421                    let iter = values.iter().map(|val| val.to_string());
422                    tokens.extend(iter);
423                }
424                F::U8(values) => {
425                    let iter = values.iter().map(|val| val.to_string());
426                    tokens.extend(iter);
427                }
428                F::U16(values) => {
429                    let iter = values.iter().map(|val| val.to_string());
430                    tokens.extend(iter);
431                }
432                F::U32(values) => {
433                    let iter = values.iter().map(|val| val.to_string());
434                    tokens.extend(iter);
435                }
436                F::U64(values) => {
437                    let iter = values.iter().map(|val| val.to_string());
438                    tokens.extend(iter);
439                }
440                F::F32(values) => {
441                    let iter = values.iter().map(|val| val.to_string());
442                    tokens.extend(iter);
443                }
444                F::F64(values) => {
445                    let iter = values.iter().map(|val| val.to_string());
446                    tokens.extend(iter);
447                }
448            }
449        }
450
451        writeln!(writer, "{}", tokens.join(" "))?;
452
453        Ok(())
454    }
455}
456
457impl PcdDeserialize for DynRecord {
458    fn is_dynamic() -> bool {
459        true
460    }
461
462    fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
463        unreachable!();
464    }
465
466    fn read_chunk<R: BufRead>(reader: &mut R, field_defs: &Schema) -> Result<Self> {
467        use Field as F;
468        use ValueKind as K;
469
470        let mut fields = Vec::with_capacity(field_defs.len());
471
472        for def in field_defs.iter() {
473            let FieldDef {
474                kind, count, name, ..
475            } = def;
476            let count = *count;
477
478            // For padding fields, read and discard the bytes
479            if name == "_" {
480                let skip_bytes = kind.byte_size() * count as usize;
481                let mut discard = vec![0u8; skip_bytes];
482                reader.read_exact(&mut discard)?;
483                continue;
484            }
485
486            let counter = 0..count;
487
488            let field = match kind {
489                K::I8 => {
490                    let values = counter
491                        .map(|_| Ok(reader.read_i8()?))
492                        .collect::<Result<Vec<_>>>()?;
493                    F::I8(values)
494                }
495                K::I16 => {
496                    let values = counter
497                        .map(|_| Ok(reader.read_i16::<LittleEndian>()?))
498                        .collect::<Result<Vec<_>>>()?;
499                    F::I16(values)
500                }
501                K::I32 => {
502                    let values = counter
503                        .map(|_| Ok(reader.read_i32::<LittleEndian>()?))
504                        .collect::<Result<Vec<_>>>()?;
505                    F::I32(values)
506                }
507                K::I64 => {
508                    let values = counter
509                        .map(|_| Ok(reader.read_i64::<LittleEndian>()?))
510                        .collect::<Result<Vec<_>>>()?;
511                    F::I64(values)
512                }
513                K::U8 => {
514                    let values = counter
515                        .map(|_| Ok(reader.read_u8()?))
516                        .collect::<Result<Vec<_>>>()?;
517                    F::U8(values)
518                }
519                K::U16 => {
520                    let values = counter
521                        .map(|_| Ok(reader.read_u16::<LittleEndian>()?))
522                        .collect::<Result<Vec<_>>>()?;
523                    F::U16(values)
524                }
525                K::U32 => {
526                    let values = counter
527                        .map(|_| Ok(reader.read_u32::<LittleEndian>()?))
528                        .collect::<Result<Vec<_>>>()?;
529                    F::U32(values)
530                }
531                K::U64 => {
532                    let values = counter
533                        .map(|_| Ok(reader.read_u64::<LittleEndian>()?))
534                        .collect::<Result<Vec<_>>>()?;
535                    F::U64(values)
536                }
537                K::F32 => {
538                    let values = counter
539                        .map(|_| Ok(reader.read_f32::<LittleEndian>()?))
540                        .collect::<Result<Vec<_>>>()?;
541                    F::F32(values)
542                }
543                K::F64 => {
544                    let values = counter
545                        .map(|_| Ok(reader.read_f64::<LittleEndian>()?))
546                        .collect::<Result<Vec<_>>>()?;
547                    F::F64(values)
548                }
549            };
550
551            fields.push(field);
552        }
553
554        Ok(Self(fields))
555    }
556
557    fn read_line<R: BufRead>(reader: &mut R, field_defs: &Schema) -> Result<Self> {
558        let mut line = String::new();
559        reader.read_line(&mut line)?;
560        let tokens = line.split_ascii_whitespace().collect::<Vec<_>>();
561
562        {
563            let expect = field_defs.iter().map(|def| def.count as usize).sum();
564            if tokens.len() != expect {
565                return Err(Error::new_text_token_mismatch_error(expect, tokens.len()));
566            }
567        }
568
569        let mut tokens_iter = tokens.into_iter();
570
571        let mut fields = Vec::with_capacity(field_defs.len());
572
573        for def in field_defs.iter() {
574            let FieldDef {
575                kind, count, name, ..
576            } = def;
577            let count = *count as usize;
578
579            // For padding fields, consume tokens but don't add to fields
580            if name == "_" {
581                for _ in 0..count {
582                    tokens_iter.next();
583                }
584                continue;
585            }
586
587            let field = match kind {
588                ValueKind::I8 => {
589                    let values: Vec<i8> = (&mut tokens_iter)
590                        .map(|token| token.parse())
591                        .take(count)
592                        .try_collect()?;
593                    Field::I8(values)
594                }
595                ValueKind::I16 => {
596                    let values: Vec<i16> = (&mut tokens_iter)
597                        .map(|token| token.parse())
598                        .take(count)
599                        .try_collect()?;
600                    Field::I16(values)
601                }
602                ValueKind::I32 => {
603                    let values: Vec<i32> = (&mut tokens_iter)
604                        .map(|token| token.parse())
605                        .take(count)
606                        .try_collect()?;
607                    Field::I32(values)
608                }
609                ValueKind::I64 => {
610                    let values: Vec<i64> = (&mut tokens_iter)
611                        .map(|token| token.parse())
612                        .take(count)
613                        .try_collect()?;
614                    Field::I64(values)
615                }
616                ValueKind::U8 => {
617                    let values: Vec<u8> = (&mut tokens_iter)
618                        .map(|token| token.parse())
619                        .take(count)
620                        .try_collect()?;
621                    Field::U8(values)
622                }
623                ValueKind::U16 => {
624                    let values: Vec<u16> = (&mut tokens_iter)
625                        .map(|token| token.parse())
626                        .take(count)
627                        .try_collect()?;
628                    Field::U16(values)
629                }
630                ValueKind::U32 => {
631                    let values: Vec<u32> = (&mut tokens_iter)
632                        .map(|token| token.parse())
633                        .take(count)
634                        .try_collect()?;
635                    Field::U32(values)
636                }
637                ValueKind::U64 => {
638                    let values: Vec<u64> = (&mut tokens_iter)
639                        .map(|token| token.parse())
640                        .take(count)
641                        .try_collect()?;
642                    Field::U64(values)
643                }
644                ValueKind::F32 => {
645                    let values: Vec<f32> = (&mut tokens_iter)
646                        .map(|token| token.parse())
647                        .take(count)
648                        .try_collect()?;
649                    Field::F32(values)
650                }
651                ValueKind::F64 => {
652                    let values: Vec<f64> = (&mut tokens_iter)
653                        .map(|token| token.parse())
654                        .take(count)
655                        .try_collect()?;
656                    Field::F64(values)
657                }
658            };
659
660            fields.push(field);
661        }
662
663        Ok(Self(fields))
664    }
665}
666
667// impl for primitive types
668
669impl PcdDeserialize for u8 {
670    fn is_dynamic() -> bool {
671        false
672    }
673
674    fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
675        vec![(None, ValueKind::U8, Some(1))]
676    }
677
678    fn read_chunk<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
679        let value = reader.read_u8()?;
680        Ok(value)
681    }
682
683    fn read_line<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
684        let mut line = String::new();
685        reader.read_line(&mut line)?;
686        Ok(line.parse()?)
687    }
688}
689
690impl PcdDeserialize for i8 {
691    fn is_dynamic() -> bool {
692        false
693    }
694
695    fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
696        vec![(None, ValueKind::I8, Some(1))]
697    }
698
699    fn read_chunk<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
700        let value = reader.read_i8()?;
701        Ok(value)
702    }
703
704    fn read_line<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
705        let mut line = String::new();
706        reader.read_line(&mut line)?;
707        Ok(line.parse()?)
708    }
709}
710
711macro_rules! impl_primitive {
712    ($ty:ty, $kind:ident, $read:ident) => {
713        impl PcdDeserialize for $ty {
714            fn is_dynamic() -> bool {
715                false
716            }
717
718            fn read_spec() -> Vec<(Option<String>, ValueKind, Option<usize>)> {
719                vec![(None, ValueKind::$kind, Some(1))]
720            }
721
722            fn read_chunk<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
723                let value = reader.$read::<LittleEndian>()?;
724                Ok(value)
725            }
726
727            fn read_line<R: BufRead>(reader: &mut R, _field_defs: &Schema) -> Result<Self> {
728                let mut line = String::new();
729                reader.read_line(&mut line)?;
730                Ok(line.parse()?)
731            }
732        }
733    };
734}
735
736impl_primitive!(u16, U16, read_u16);
737impl_primitive!(u32, U32, read_u32);
738impl_primitive!(u64, U64, read_u64);
739impl_primitive!(i16, I16, read_i16);
740impl_primitive!(i32, I32, read_i32);
741impl_primitive!(i64, I64, read_i64);
742impl_primitive!(f32, F32, read_f32);
743impl_primitive!(f64, F64, read_f64);