use bytes::{Buf, BytesMut};
use moqtap_codec::dispatch::{AnyFetchHeader, AnyObjectHeader, AnySubgroupHeader};
use moqtap_codec::version::DraftVersion;
use crate::event::DataStreamHeaderKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataStreamType {
Subgroup,
Fetch,
}
#[derive(Debug)]
enum DataStreamState {
AwaitingHeader,
InStream,
}
#[derive(Debug)]
pub enum DataParseResult {
Header(DataStreamHeaderKind),
Object(AnyObjectHeader),
NeedMore,
Error(String),
}
pub struct DataStreamParser {
buf: BytesMut,
stream_type: DataStreamType,
state: DataStreamState,
draft: DraftVersion,
}
impl DataStreamParser {
pub fn new(stream_type: DataStreamType, draft: DraftVersion) -> Self {
Self {
buf: BytesMut::with_capacity(4096),
stream_type,
state: DataStreamState::AwaitingHeader,
draft,
}
}
pub fn feed(&mut self, data: &[u8]) -> Vec<DataParseResult> {
self.buf.extend_from_slice(data);
let mut results = Vec::new();
loop {
if self.buf.is_empty() {
break;
}
match self.state {
DataStreamState::AwaitingHeader => match self.try_parse_header() {
Some(Ok(header)) => {
self.state = DataStreamState::InStream;
results.push(DataParseResult::Header(header));
}
Some(Err(e)) => {
results.push(DataParseResult::Error(e));
break;
}
None => {
if results.is_empty() {
results.push(DataParseResult::NeedMore);
}
break;
}
},
DataStreamState::InStream => match self.try_parse_object() {
Some(Ok(header)) => {
results.push(DataParseResult::Object(header));
}
Some(Err(e)) => {
results.push(DataParseResult::Error(e));
break;
}
None => {
if results.is_empty() {
results.push(DataParseResult::NeedMore);
}
break;
}
},
}
}
results
}
fn try_parse_header(&mut self) -> Option<Result<DataStreamHeaderKind, String>> {
let snapshot = &self.buf[..];
let mut cursor = snapshot;
match self.stream_type {
DataStreamType::Subgroup => match AnySubgroupHeader::decode(self.draft, &mut cursor) {
Ok(header) => {
let consumed = snapshot.len() - cursor.remaining();
self.buf.advance(consumed);
Some(Ok(DataStreamHeaderKind::Subgroup(header)))
}
Err(e) => {
if is_incomplete_error(&e) {
None
} else {
Some(Err(format!("subgroup header decode: {e}")))
}
}
},
DataStreamType::Fetch => match AnyFetchHeader::decode(self.draft, &mut cursor) {
Ok(header) => {
let consumed = snapshot.len() - cursor.remaining();
self.buf.advance(consumed);
Some(Ok(DataStreamHeaderKind::Fetch(header)))
}
Err(e) => {
if is_incomplete_error(&e) {
None
} else {
Some(Err(format!("fetch header decode: {e}")))
}
}
},
}
}
fn try_parse_object(&mut self) -> Option<Result<AnyObjectHeader, String>> {
let snapshot = &self.buf[..];
let mut cursor = snapshot;
match AnyObjectHeader::decode(self.draft, &mut cursor) {
Ok(header) => {
let consumed = snapshot.len() - cursor.remaining();
self.buf.advance(consumed);
Some(Ok(header))
}
Err(e) => {
if is_incomplete_error(&e) {
None
} else {
Some(Err(format!("object header decode: {e}")))
}
}
}
}
}
fn is_incomplete_error(e: &moqtap_codec::error::CodecError) -> bool {
matches!(e, moqtap_codec::error::CodecError::UnexpectedEnd)
|| matches!(
e,
moqtap_codec::error::CodecError::VarInt(
moqtap_codec::varint::VarIntError::UnexpectedEnd
)
)
}