use deku::reader::Reader;
use deku::DekuReader;
use crate::decode::nmea::{MessageAssembler, NmeaAisMessage, NmeaError};
use crate::prelude::Message;
use std::fs::File;
use std::io::{BufRead, BufReader, Cursor, Lines};
use std::path::Path;
pub struct NmeaIterator<R: BufRead> {
lines: Lines<R>,
assembler: MessageAssembler,
}
impl<R: BufRead> NmeaIterator<R> {
pub fn new(reader: R) -> Self {
Self {
lines: reader.lines(),
assembler: MessageAssembler::new(),
}
}
pub fn next_complete_message(&mut self) -> Option<Result<Message, NmeaError>> {
loop {
let line = match self.lines.next() {
Some(Ok(line)) => line,
Some(Err(_)) => return None, None => return None, };
let line = line.trim();
let nmea_msg = match NmeaAisMessage::parse(line) {
Ok(msg) => msg,
Err(e) => return Some(Err(e)),
};
match self.assembler.add_fragment(nmea_msg) {
Ok(Some(complete_message)) => {
let cursor = Cursor::new(complete_message);
let mut reader = Reader::new(cursor);
return Some(Ok(Message::from_reader_with_ctx(&mut reader, ()).ok()?));
}
Ok(None) => continue, Err(e) => return Some(Err(e)),
}
}
}
}
impl<R: BufRead> Iterator for NmeaIterator<R> {
type Item = Result<Message, NmeaError>;
fn next(&mut self) -> Option<Self::Item> {
self.next_complete_message()
}
}
pub struct NmeaFileSource {
iterator: NmeaIterator<BufReader<File>>,
}
impl NmeaFileSource {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, std::io::Error> {
let file = File::open(path)?;
let reader = BufReader::new(file);
Ok(Self {
iterator: NmeaIterator::new(reader),
})
}
}
impl Iterator for NmeaFileSource {
type Item = Result<Message, NmeaError>;
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next()
}
}
pub fn from_reader<R: BufRead>(reader: R) -> NmeaIterator<R> {
NmeaIterator::new(reader)
}