use crate::point::Point;
use crate::source::Source;
use crate::units::Radians;
use crate::Error;
use byteorder::{LittleEndian, ReadBytesExt};
use std::fmt::Debug;
use std::fs::File;
use std::io::{BufReader, Read};
use std::iter::IntoIterator;
use std::path::Path;
#[derive(Debug)]
pub struct Reader<R: Read> {
reader: R,
}
impl Reader<BufReader<File>> {
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>, std::io::Error> {
Ok(Reader {
reader: BufReader::new(File::open(path)?),
})
}
}
impl<R: Read> Reader<R> {
pub fn read_point(&mut self) -> Result<Option<Point>, std::io::Error> {
use std::io::ErrorKind;
let time = match self.reader.read_f64::<LittleEndian>() {
Ok(time) => time,
Err(err) => match err.kind() {
ErrorKind::UnexpectedEof => return Ok(None),
_ => return Err(err.into()),
},
};
Ok(Some(Point {
time,
latitude: Radians(self.reader.read_f64::<LittleEndian>()?),
longitude: Radians(self.reader.read_f64::<LittleEndian>()?),
altitude: self.reader.read_f64::<LittleEndian>()?,
x_velocity: Some(self.reader.read_f64::<LittleEndian>()?),
y_velocity: Some(self.reader.read_f64::<LittleEndian>()?),
z_velocity: Some(self.reader.read_f64::<LittleEndian>()?),
roll: Radians(self.reader.read_f64::<LittleEndian>()?),
pitch: Radians(self.reader.read_f64::<LittleEndian>()?),
yaw: Radians(self.reader.read_f64::<LittleEndian>()?),
wander_angle: Some(Radians(self.reader.read_f64::<LittleEndian>()?)),
x_acceleration: Some(self.reader.read_f64::<LittleEndian>()?),
y_acceleration: Some(self.reader.read_f64::<LittleEndian>()?),
z_acceleration: Some(self.reader.read_f64::<LittleEndian>()?),
x_angular_rate: Some(Radians(self.reader.read_f64::<LittleEndian>()?)),
y_angular_rate: Some(Radians(self.reader.read_f64::<LittleEndian>()?)),
z_angular_rate: Some(Radians(self.reader.read_f64::<LittleEndian>()?)),
..Default::default()
}))
}
}
impl<R: Read> IntoIterator for Reader<R> {
type Item = Point;
type IntoIter = ReaderIterator<R>;
fn into_iter(self) -> Self::IntoIter {
ReaderIterator { reader: self }
}
}
#[derive(Debug)]
pub struct ReaderIterator<R: Read> {
reader: Reader<R>,
}
impl<R: Read> Iterator for ReaderIterator<R> {
type Item = Point;
fn next(&mut self) -> Option<Self::Item> {
self.reader.read_point().unwrap()
}
}
impl<R: Debug + Read> Source for Reader<R> {
fn source(&mut self) -> Result<Option<Point>, Error> {
self.read_point().map_err(Error::from)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_file() {
let reader = Reader::from_path("data/2-points.sbet").unwrap();
let points: Vec<_> = reader.into_iter().collect();
assert_eq!(2, points.len());
let point = points[0];
assert!((1.5163100e5 - point.time).abs() < 1e-2, "{}", point.time);
assert!(
(0.5680211 - point.latitude.0).abs() < 1e-7,
"{:?}",
point.latitude
);
assert!(
(1.5163110e5 - points[1].time).abs() < 1e-1,
"{}",
points[1].time
);
}
}