1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use std::fs::File;
use std::path::Path;
use std::{result, str};
use std::iter::Iterator;
use std::io::{self, Read};
use memmap::Mmap;
const VERSION_STRING: &str = "#ROSBAG V2.0\n";
mod record;
mod field_iter;
mod cursor;
mod error;
pub mod msg_iter;
pub mod record_types;
pub use record::Record;
pub use error::Error;
use cursor::Cursor;
pub struct RosBag {
data: Mmap,
}
pub type Result<T> = result::Result<T, Error>;
impl RosBag {
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let mut file = File::open(path)?;
let mut buf = [0u8; 13];
file.read_exact(&mut buf)?;
if buf != VERSION_STRING.as_bytes() {
return Err(io::Error::new(io::ErrorKind::InvalidData,
"Invalid or unsupported rosbag header"));
}
let data = unsafe { Mmap::map(&file)? };
Ok(Self { data })
}
pub fn records(&self) -> RecordsIterator<'_> {
let mut cursor = Cursor::new(&self.data);
cursor.seek(VERSION_STRING.len() as u64)
.expect("data header is checked on initialization");
RecordsIterator { cursor }
}
}
pub struct RecordsIterator<'a> {
cursor: Cursor<'a>,
}
impl<'a> RecordsIterator<'a> {
pub fn seek(&mut self, pos: u64) -> Result<()> {
Ok(self.cursor.seek(pos)?)
}
}
impl<'a> Iterator for RecordsIterator<'a> {
type Item = Result<Record<'a>>;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor.left() == 0 { return None; }
Some(Record::next_record(&mut self.cursor))
}
}