1use std::{fs, io, path};
16use hex::FromHex;
17
18fn parse_raw(bytes: &[u8], radix: u32) -> Option<u64> {
20 ::std::str::from_utf8(bytes)
21 .ok()
22 .and_then(|s| u64::from_str_radix(s, radix).ok())
23}
24
25#[derive(Debug)]
26pub struct Reader<R> {
28 rdr: R,
29 line_buf: Vec<u8>,
30}
31
32impl<R: io::Read> Reader<R> {
33 pub fn from_reader(rdr: R) -> Reader<io::BufReader<R>> {
34 Reader {
35 rdr: io::BufReader::new(rdr),
36 line_buf: Vec::new(),
37 }
38 }
39}
40
41impl Reader<fs::File> {
42 pub fn from_file<P: AsRef<path::Path>>(path: P) -> io::Result<Reader<io::BufReader<fs::File>>> {
43 Ok(Reader::from_reader(fs::File::open(path)?))
44 }
45}
46
47#[derive(Debug)]
49pub struct CanDumpRecords<'a, R: 'a> {
50 src: &'a mut Reader<R>,
51}
52
53#[derive(Debug)]
55pub struct CanDumpRecord<'a> {
56 pub t_us: u64,
57 pub device: &'a str,
58 pub frame: super::CanFrame,
59}
60
61#[derive(Debug)]
62pub enum ParseError {
64 Io(io::Error),
65 UnexpectedEndOfLine,
66 InvalidTimestamp,
67 InvalidDeviceName,
68 InvalidCanFrame,
69 ConstructionError(super::ConstructionError),
70}
71
72impl From<io::Error> for ParseError {
73 fn from(e: io::Error) -> ParseError {
74 ParseError::Io(e)
75 }
76}
77
78impl From<super::ConstructionError> for ParseError {
79 fn from(e: super::ConstructionError) -> ParseError {
80 ParseError::ConstructionError(e)
81 }
82}
83
84impl<R: io::BufRead> Reader<R> {
85 pub fn records(&mut self) -> CanDumpRecords<R> {
87 CanDumpRecords { src: self }
88 }
89
90 pub fn next_record(&mut self) -> Result<Option<CanDumpRecord>, ParseError> {
92 self.line_buf.clear();
93 let bytes_read = self.rdr.read_until(b'\n', &mut self.line_buf)?;
94
95 if bytes_read == 0 {
97 return Ok(None);
98 }
99
100 let mut field_iter = self.line_buf.split(|&c| c == b' ');
101
102 let f = field_iter.next().ok_or(ParseError::UnexpectedEndOfLine)?;
104
105 if f.len() < 3 || f[0] != b'(' || f[f.len() - 1] != b')' {
106 return Err(ParseError::InvalidTimestamp);
107 }
108
109 let inner = &f[1..f.len() - 1];
110
111 let dot = inner.iter()
113 .position(|&c| c == b'.')
114 .ok_or(ParseError::InvalidTimestamp)?;
115
116 let (num, mant) = inner.split_at(dot);
117
118 let n_num: u64 = parse_raw(num, 10).ok_or(ParseError::InvalidTimestamp)?;
120 let n_mant: u64 = parse_raw(&mant[1..], 10).ok_or(ParseError::InvalidTimestamp)?;
121 let t_us = n_num.saturating_mul(1_000_000).saturating_add(n_mant);
122
123 let f = field_iter.next().ok_or(ParseError::UnexpectedEndOfLine)?;
124
125 let device = ::std::str::from_utf8(f).map_err(|_| ParseError::InvalidDeviceName)?;
127
128 let can_raw = field_iter.next()
130 .ok_or(ParseError::UnexpectedEndOfLine)?;
131
132 let sep_idx = can_raw.iter()
133 .position(|&c| c == b'#')
134 .ok_or(ParseError::InvalidCanFrame)?;
135 let (can_id, mut can_data) = can_raw.split_at(sep_idx);
136
137 can_data = &can_data[1..];
139 if let Some(&b'\n') = can_data.last() {
140 can_data = &can_data[..can_data.len() - 1];
141 };
142
143 let rtr = b"R" == can_data;
144
145 let data = if rtr {
146 Vec::new()
147 } else {
148 Vec::from_hex(&can_data).map_err(|_| ParseError::InvalidCanFrame)?
149 };
150 let frame = super::CanFrame::new((parse_raw(can_id, 16)
151 .ok_or
152
153
154 (ParseError::InvalidCanFrame))?
155 as u32,
156 &data,
157 rtr,
158 false)?;
160
161 Ok(Some(CanDumpRecord {
162 t_us,
163 device,
164 frame,
165 }))
166 }
167}
168
169impl<'a, R: io::Read> Iterator for CanDumpRecords<'a, io::BufReader<R>> {
170 type Item = Result<(u64, super::CanFrame), ParseError>;
171
172 fn next(&mut self) -> Option<Self::Item> {
173 match self.src.next_record() {
175 Ok(Some(CanDumpRecord { t_us, frame, .. })) => Some(Ok((t_us, frame))),
176 Ok(None) => None,
177 Err(e) => Some(Err(e)),
178 }
179 }
180}
181
182#[cfg(test)]
183mod test {
184 use super::Reader;
185
186 #[test]
187 fn test_simple_example() {
188 let input: &[u8] = b"(1469439874.299591) can1 080#\n\
189 (1469439874.299654) can1 701#7F";
190
191 let mut reader = Reader::from_reader(input);
192
193 {
194 let rec1 = reader.next_record().unwrap().unwrap();
195
196 assert_eq!(rec1.t_us, 1469439874299591);
197 assert_eq!(rec1.device, "can1");
198 assert_eq!(rec1.frame.id(), 0x080);
199 assert_eq!(rec1.frame.is_rtr(), false);
200 assert_eq!(rec1.frame.is_error(), false);
201 assert_eq!(rec1.frame.is_extended(), false);
202 assert_eq!(rec1.frame.data(), &[]);
203 }
204
205 {
206 let rec2 = reader.next_record().unwrap().unwrap();
207 assert_eq!(rec2.t_us, 1469439874299654);
208 assert_eq!(rec2.device, "can1");
209 assert_eq!(rec2.frame.id(), 0x701);
210 assert_eq!(rec2.frame.is_rtr(), false);
211 assert_eq!(rec2.frame.is_error(), false);
212 assert_eq!(rec2.frame.is_extended(), false);
213 assert_eq!(rec2.frame.data(), &[0x7F]);
214 }
215
216 assert!(reader.next_record().unwrap().is_none());
217 }
218
219
220}