use std::collections::VecDeque;
use std::io;
use crate::canonical::Event;
use crate::protocol::{DecodeState, Decoder, Frame, Protocol};
use crate::transport::Bytes;
use super::{premature_eof_with_body, transport_err};
const PREMATURE_EOF_BODY_CAP: usize = 8 * 1024;
pub(super) struct StreamEvents {
proto: &'static dyn Protocol,
body: Box<dyn Iterator<Item = io::Result<Bytes>>>,
decoder: Box<dyn Decoder>,
state: DecodeState,
pending: VecDeque<Event>,
body_done: bool,
finished: bool,
saw_frame: bool,
head: Vec<u8>,
}
impl StreamEvents {
pub(super) fn new(
proto: &'static dyn Protocol,
body: Box<dyn Iterator<Item = io::Result<Bytes>>>,
) -> Self {
StreamEvents {
decoder: proto.framing().decoder(),
proto,
body,
state: DecodeState::default(),
pending: VecDeque::new(),
body_done: false,
finished: false,
saw_frame: false,
head: Vec::new(),
}
}
fn decode_into_pending(&mut self, frame: Frame) {
self.saw_frame = true;
self.head = Vec::new();
match self.proto.decode(frame, &mut self.state) {
Ok(events) => self.pending.extend(events),
Err(e) => self.pending.push_back(Event::Error(e)),
}
}
fn accumulate_head(&mut self, chunk: &[u8]) {
if self.saw_frame {
return;
}
let room = PREMATURE_EOF_BODY_CAP.saturating_sub(self.head.len());
self.head.extend_from_slice(&chunk[..room.min(chunk.len())]);
}
fn premature_eof(&self) -> Event {
Event::Error(if self.saw_frame {
transport_err("premature upstream EOF")
} else {
premature_eof_with_body(&self.head)
})
}
fn close_open_blocks(&mut self) {
let mut open: Vec<u32> = self.state.open.keys().copied().collect();
open.sort_unstable();
for index in open {
self.state.open.remove(&index);
self.pending.push_back(Event::ContentStop { index });
}
}
}
impl Iterator for StreamEvents {
type Item = Event;
fn next(&mut self) -> Option<Event> {
loop {
if let Some(ev) = self.pending.pop_front() {
return Some(ev);
}
if self.finished {
return None;
}
if self.body_done {
let tail = self.decoder.finish().unwrap_or_default();
for frame in tail {
self.decode_into_pending(frame);
}
if !self.state.terminated {
self.close_open_blocks();
self.pending.push_back(self.premature_eof());
}
self.finished = true;
continue;
}
match self.body.next() {
Some(Ok(chunk)) => {
self.accumulate_head(&chunk);
for frame in self.decoder.push(chunk).unwrap_or_default() {
self.decode_into_pending(frame);
}
}
Some(Err(_)) => {
self.close_open_blocks();
self.pending
.push_back(Event::Error(transport_err("transport stream dropped")));
self.finished = true;
}
None => self.body_done = true,
}
}
}
}