use std::io;
use crate::codec::{Decoder, Error, check_header, framed};
use crate::model::{Timeline, Trace};
const COMPACT_PAST: usize = 1 << 16;
#[derive(Default)]
pub struct Stream {
buf: Vec<u8>,
at: usize,
header: bool,
dec: Decoder,
trace: Trace,
timeline: Timeline,
}
impl Stream {
pub fn new() -> Self {
Stream {
trace: Trace::new(),
..Default::default()
}
}
pub fn push(&mut self, bytes: &[u8]) -> Result<usize, Error> {
self.buf.extend_from_slice(bytes);
if !self.header {
match check_header(&self.buf)? {
Some(n) => {
self.at = n;
self.header = true;
}
None => return Ok(0),
}
}
let from = self.trace.records.len();
let mut came = 0;
while let Some((tag, body)) = framed(&self.buf, self.at) {
self.at = body.end;
if let Some(Some(r)) = self.dec.decode(tag, &self.buf[body]) {
self.trace.push(r);
came += 1;
}
}
self.timeline.extend(&self.trace.records[from..]);
if self.at > COMPACT_PAST {
self.buf.drain(..self.at);
self.at = 0;
}
Ok(came)
}
pub fn reset(&mut self) {
*self = Stream::new();
}
pub fn trace(&self) -> &Trace {
&self.trace
}
pub fn timeline(&self) -> &Timeline {
&self.timeline
}
pub fn started(&self) -> bool {
self.header
}
pub fn pending(&self) -> usize {
self.buf.len() - self.at
}
pub fn poll(&mut self, t: &mut dyn Transport) -> Result<Polled, PollError> {
let mut buf = Vec::new();
match t.poll(&mut buf).map_err(PollError::Io)? {
Polled::Reset => {
self.reset();
self.push(&buf).map_err(PollError::Trace)?;
Ok(Polled::Reset)
}
Polled::More(_) => Ok(Polled::More(self.push(&buf).map_err(PollError::Trace)?)),
other => Ok(other),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Polled {
More(usize),
Idle,
Ended,
Reset,
}
pub trait Transport: Send {
fn poll(&mut self, buf: &mut Vec<u8>) -> io::Result<Polled>;
}
#[derive(Debug)]
pub enum PollError {
Io(io::Error),
Trace(Error),
}
impl std::fmt::Display for PollError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PollError::Io(e) => write!(f, "{e}"),
PollError::Trace(e) => write!(f, "{e}"),
}
}
}
impl std::error::Error for PollError {}