use std::{
io,
pin::Pin,
task::{Context, Poll},
};
use bytes::Bytes;
use futures::{SinkExt, StreamExt, TryStream, sink};
use crate::{
codec::{DecodeExt, DecodeStreamError, FixedLengthReader, StreamReader},
connection::StreamError,
dhttp::frame::Frame,
error::H3FrameDecodeError,
quic::{self, GetStreamId, StopStream},
varint::VarInt,
};
pin_project_lite::pin_project! {
pub struct FrameStream<S: ?Sized> {
frame: Option<Result<Frame<()>, StreamError>>,
#[pin]
stream: FixedLengthReader<StreamReader<S>>,
}
}
pub type ReadableFrame<'s, S> = Frame<Pin<&'s mut FixedLengthReader<StreamReader<S>>>>;
impl<S: ?Sized + Send> FrameStream<S>
where
S: TryStream<Ok = Bytes, Error = quic::StreamError>,
{
pub const fn new(stream: StreamReader<S>) -> Self
where
S: Sized,
{
Self {
stream: FixedLengthReader::new(stream, 0),
frame: None,
}
}
fn project_stream_mut(self: Pin<&mut Self>) -> Pin<&mut StreamReader<S>> {
self.project().stream.project_stream_mut()
}
pub(crate) fn inner_mut(&mut self) -> &mut S
where
S: Sized,
{
self.stream.stream_mut().stream_mut()
}
pub fn frame<'s>(self: Pin<&'s mut Self>) -> Option<Result<ReadableFrame<'s, S>, StreamError>> {
match self.frame.as_ref()? {
Ok(frame) => Some(Ok(Frame {
r#type: frame.r#type,
length: frame.length,
payload: self.project().stream,
})),
Err(error) => Some(Err(error.clone())),
}
}
pub async fn consume_current_frame(mut self: Pin<&mut Self>) -> Result<(), StreamError> {
let map_decode_stream_error = |error: DecodeStreamError| {
error.map_decode_error(|decode_error| {
H3FrameDecodeError {
source: decode_error,
}
.into()
})
};
match self.as_mut().frame() {
Some(Ok(mut frame)) => {
let mut drain = sink::drain().sink_map_err(|never| match never {});
let result = (&mut frame).forward(&mut drain).await;
if let Err(error) = result.map_err(map_decode_stream_error) {
*self.project().frame = Some(Err(error.clone()));
return Err(error);
}
*self.project().frame = None;
Ok(())
}
Some(Err(error)) => Err(error.clone()),
None => Ok(()),
}
}
pub async fn decode_next_frame(mut self: Pin<&mut Self>) {
let try_decode_next_frame = async {
self.as_mut().consume_current_frame().await?;
let mut stream = self.as_mut().project_stream_mut();
if !stream.as_mut().has_remaining().await? {
return Ok(None);
}
let convert_decode_varint_error = |error: io::Error| {
DecodeStreamError::from(error).map_decode_error(|decode_error| {
H3FrameDecodeError {
source: decode_error,
}
.into()
})
};
let r#type =
(stream.decode_one::<VarInt>().await).map_err(convert_decode_varint_error)?;
let length =
(stream.decode_one::<VarInt>().await).map_err(convert_decode_varint_error)?;
Ok(Some(Frame {
r#type,
length,
payload: (),
}))
};
match try_decode_next_frame.await {
Ok(Some(frame)) => {
let project = self.project();
project.stream.renew(frame.length.into_inner());
*project.frame = Some(Ok(frame));
}
Ok(None) => *self.project().frame = None,
Err(error) => *self.project().frame = Some(Err(error)),
}
}
pub async fn next_frame(
mut self: Pin<&mut Self>,
) -> Option<Result<ReadableFrame<'_, S>, StreamError>> {
self.as_mut().decode_next_frame().await;
self.frame()
}
pub async fn decode_next_unreserved_frame(mut self: Pin<&mut Self>) {
loop {
match self.as_mut().next_frame().await {
Some(Ok(frame)) if frame.is_reserved_frame() => continue,
_decoded => break,
}
}
}
pub async fn next_unreserved_frame(
mut self: Pin<&mut Self>,
) -> Option<Result<ReadableFrame<'_, S>, StreamError>> {
self.as_mut().decode_next_unreserved_frame().await;
self.frame()
}
}
impl<S: GetStreamId + ?Sized> GetStreamId for FrameStream<S> {
fn poll_stream_id(
self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Result<VarInt, quic::StreamError>> {
self.project().stream.poll_stream_id(cx)
}
}
impl<S: StopStream + ?Sized> StopStream for FrameStream<S> {
fn poll_stop(
self: Pin<&mut Self>,
cx: &mut Context,
code: VarInt,
) -> Poll<Result<(), quic::StreamError>> {
self.project().stream.poll_stop(cx, code)
}
}