libexail 0.1.0

A rust library for communicating with Exail devices through their binary protocol
Documentation
//! Iterator-based reader for Exail frames over byte streams.

use crate::{blocks::Message, parser::ExailParser};
use std::io::Read;

const BUFFER_SIZE: usize = 1024 * 8;

/// Read Exail frames via a buffered reader and iterator.
///
/// # Examples
///
/// ```no_run
/// use libexail::reader::ExailReader;
/// use std::net::TcpStream;
///
/// let stream = TcpStream::connect("127.0.0.1:8080").unwrap();
/// let reader = ExailReader::new(stream);
/// for message in reader {
///     match message {
///         Ok(m) => eprintln!("{:?}", m),
///         Err(e) => eprintln!("Error: {:?}", e),
///     }
/// }
/// ```
pub struct ExailReader<R: Read> {
    reader: R,
    parser: ExailParser,
    drain_internal: bool,
}

impl<R: Read> ExailReader<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            parser: ExailParser::new(),
            drain_internal: false,
        }
    }
}

impl<R: Read> Iterator for ExailReader<R> {
    type Item = Result<Message, std::io::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut buffer = [0u8; BUFFER_SIZE];
        loop {
            let (bytes_read, is_eof) = if self.drain_internal {
                (0, false)
            } else {
                match self.reader.read(&mut buffer) {
                    Ok(br) => (br, br == 0),
                    Err(e) => return Some(Err(e)),
                }
            };

            match self.parser.consume(&buffer[..bytes_read]) {
                Some(message) => {
                    self.drain_internal = true;
                    return Some(Ok(message));
                }
                None => {
                    self.drain_internal = false;
                }
            }

            if is_eof {
                return None;
            }
        }
    }
}