use crate::pof;
use crate::point::{Accuracy, Point};
use crate::poq;
use crate::Error;
use std::fmt::Debug;
use std::fs::File;
use std::io::{BufReader, Read, Seek};
use std::iter::IntoIterator;
use std::path::Path;
pub trait Source: Debug {
fn source(&mut self) -> Result<Option<Point>, Error>;
}
impl IntoIterator for Box<dyn Source> {
type Item = Point;
type IntoIter = SourceIterator;
fn into_iter(self) -> Self::IntoIter {
SourceIterator { source: self }
}
}
#[derive(Debug)]
pub struct SourceIterator {
source: Box<dyn Source>,
}
impl Iterator for SourceIterator {
type Item = Point;
fn next(&mut self) -> Option<Point> {
self.source.source().unwrap()
}
}
pub trait AccuracySource: Debug {
fn source(&mut self) -> Result<Option<Accuracy>, Error>;
}
impl<R: Debug + Seek + Read> AccuracySource for poq::Reader<R> {
fn source(&mut self) -> Result<Option<Accuracy>, Error> {
self.read_accuracy().map_err(Error::from)
}
}
pub trait FileSource {
fn open_file_source<P: AsRef<Path>>(path: P) -> Result<Box<dyn Source>, Error>;
}
impl FileSource for pof::Reader<BufReader<File>> {
fn open_file_source<P: AsRef<Path>>(path: P) -> Result<Box<dyn Source>, Error> {
Ok(Box::new(pof::Reader::from_path(path)?))
}
}
pub trait FileAccuracySource {
fn open_file_accuracy_source<P: AsRef<Path>>(path: P)
-> Result<Box<dyn AccuracySource>, Error>;
}
impl FileAccuracySource for poq::Reader<BufReader<File>> {
fn open_file_accuracy_source<P: AsRef<Path>>(
path: P,
) -> Result<Box<dyn AccuracySource>, Error> {
Ok(Box::new(poq::Reader::from_path(path)?))
}
}
#[derive(Debug)]
pub struct CombinedSource {
source: Box<dyn Source>,
accuracy_source: Box<dyn AccuracySource>,
accuracies: (Option<Accuracy>, Option<Accuracy>),
}
impl CombinedSource {
pub fn new(
source: Box<dyn Source>,
mut accuracy_source: Box<dyn AccuracySource>,
) -> Result<CombinedSource, Error> {
let accuracies = (accuracy_source.source()?, accuracy_source.source()?);
Ok(CombinedSource {
source,
accuracy_source,
accuracies,
})
}
}
impl Source for CombinedSource {
fn source(&mut self) -> Result<Option<Point>, Error> {
let mut point = match self.source.source()? {
Some(point) => point,
None => return Ok(None),
};
if self.accuracies.0.is_none()
|| self.accuracies.1.is_none()
|| point.time < self.accuracies.0.unwrap().time
{
return Ok(Some(point));
}
loop {
if point.time > self.accuracies.1.unwrap().time {
self.accuracies.0 = self.accuracies.1;
self.accuracies.1 = self.accuracy_source.source()?;
} else {
break;
}
if self.accuracies.1.is_none() {
return Ok(Some(point));
}
}
point.accuracy = Some(
self.accuracies
.0
.unwrap()
.interpolate(&self.accuracies.1.unwrap(), point.time),
);
Ok(Some(point))
}
}
impl IntoIterator for CombinedSource {
type Item = Point;
type IntoIter = CombinedSourceIterator;
fn into_iter(self) -> Self::IntoIter {
CombinedSourceIterator { source: self }
}
}
#[derive(Debug)]
pub struct CombinedSourceIterator {
source: CombinedSource,
}
impl Iterator for CombinedSourceIterator {
type Item = Point;
fn next(&mut self) -> Option<Point> {
self.source.source().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use pof;
use poq;
#[test]
fn read_pof() {
let source = pof::Reader::open_file_source("data/sbet_mission_1.pof").unwrap();
let points: Vec<_> = source.into_iter().collect();
assert_eq!(1114521, points.len());
}
#[test]
fn read_pof_with_poq() {
let source = pof::Reader::open_file_source("data/sbet_mission_1.pof").unwrap();
let accuracy_source =
poq::Reader::open_file_accuracy_source("data/sbet_mission_1.poq").unwrap();
let accuracies: Vec<_> = CombinedSource::new(source, accuracy_source)
.unwrap()
.into_iter()
.take(20)
.collect();
assert_eq!(20, accuracies.len());
}
}