1#![cfg_attr(
8 feature = "derive",
9 doc = r##"
10```rust
11use pcd_rs::{PcdDeserialize, Reader};
12use std::path::Path;
13
14#[derive(PcdDeserialize)]
15pub struct Point {
16 x: f32,
17 y: f32,
18 z: f32,
19 rgb: f32,
20}
21
22fn main() -> pcd_rs::Result<()> {
23 let reader = Reader::open("test_files/ascii.pcd")?;
24 let points: Result<Vec<Point>> = reader.collect();
25 assert_eq!(points?.len(), 213);
26 Ok(())
27}
28```
29"##
30)]
31
32use crate::{
33 error::Error,
34 metas::{DataKind, FieldDef, PcdMeta},
35 record::{DynRecord, PcdDeserialize},
36 Result,
37};
38use std::{
39 fs::File,
40 io::{prelude::*, BufReader, Cursor},
41 marker::PhantomData,
42 path::Path,
43};
44
45pub type DynReader<R> = Reader<DynRecord, R>;
47
48pub struct Reader<T, R>
50where
51 R: Read,
52{
53 meta: PcdMeta,
54 record_count: usize,
55 finished: bool,
56 reader: R,
57 _phantom: PhantomData<T>,
58}
59
60impl<'a, Record> Reader<Record, BufReader<Cursor<&'a [u8]>>>
61where
62 Record: PcdDeserialize,
63{
64 pub fn from_bytes(buf: &'a [u8]) -> Result<Self> {
65 let reader = BufReader::new(Cursor::new(buf));
66 Self::from_reader(reader)
67 }
68}
69
70impl<Record, R> Reader<Record, R>
71where
72 Record: PcdDeserialize,
73 R: BufRead,
74{
75 pub fn from_reader(mut reader: R) -> Result<Self> {
76 let mut line_count = 0;
77 let meta = crate::utils::load_meta(&mut reader, &mut line_count)?;
78
79 if !Record::is_dynamic() {
81 let record_spec = Record::read_spec();
82
83 macro_rules! bail {
84 () => {
85 return Err(Error::new_reader_schema_mismatch_error(
86 record_spec.clone(),
87 meta.field_defs.fields.clone(),
88 ));
89 };
90 }
91
92 if record_spec.len() != meta.field_defs.len() {
93 bail!();
94 }
95
96 for (record_field, meta_field) in record_spec.iter().zip(meta.field_defs.iter()) {
97 let (ref name_opt, record_kind, record_count_opt) = *record_field;
98 let FieldDef {
99 name: ref meta_name,
100 kind: meta_kind,
101 count: meta_count,
102 } = *meta_field;
103
104 if record_kind != meta_kind {
105 bail!();
106 }
107
108 if let Some(name) = &name_opt {
109 if name != meta_name {
110 bail!();
111 }
112 }
113
114 if let Some(record_count) = record_count_opt {
115 if record_count != meta_count as usize {
116 bail!();
117 }
118 }
119 }
120 }
121
122 let pcd_reader = Reader {
123 meta,
124 reader,
125 record_count: 0,
126 finished: false,
127 _phantom: PhantomData,
128 };
129
130 Ok(pcd_reader)
131 }
132}
133
134impl<Record> Reader<Record, BufReader<File>>
135where
136 Record: PcdDeserialize,
137{
138 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
139 let file = BufReader::new(File::open(path.as_ref())?);
140 Self::from_reader(file)
141 }
142}
143
144impl<R, Record> Reader<Record, R>
145where
146 R: BufRead,
147{
148 pub fn meta(&self) -> &PcdMeta {
150 &self.meta
151 }
152}
153
154impl<R, Record> Iterator for Reader<Record, R>
155where
156 R: BufRead,
157 Record: PcdDeserialize,
158{
159 type Item = Result<Record>;
160
161 fn next(&mut self) -> Option<Self::Item> {
162 if self.finished {
163 return None;
164 }
165
166 let record_result = match self.meta.data {
167 DataKind::Ascii => Record::read_line(&mut self.reader, &self.meta.field_defs),
168 DataKind::Binary => Record::read_chunk(&mut self.reader, &self.meta.field_defs),
169 };
170
171 match record_result {
172 Ok(_) => {
173 self.record_count += 1;
174 if self.record_count == self.meta.num_points as usize {
175 self.finished = true;
176 }
177 }
178 Err(_) => {
179 self.finished = true;
180 }
181 }
182
183 Some(record_result)
184 }
185
186 fn size_hint(&self) -> (usize, Option<usize>) {
187 let size = self.meta.num_points as usize;
188 (size, Some(size))
189 }
190}