use std::{
io,
pin::Pin,
task::{Context, Poll},
};
use futures::{Sink, Stream};
use tokio::io::{AsyncBufRead, AsyncRead, AsyncWrite, ReadBuf};
use crate::{
codec::{DecodeExt, DecodeFrom, DecodeStreamError, EncodeExt},
connection::StreamError,
error::H3GeneralProtocolError,
quic::{self, CancelStream, GetStreamId, StopStream},
varint::VarInt,
};
pin_project_lite::pin_project! {
pub struct UnidirectionalStream<S: ?Sized> {
r#type: VarInt,
#[pin]
stream: S,
}
}
impl<S: AsyncRead + Unpin + Send> DecodeFrom<S> for UnidirectionalStream<S> {
type Error = StreamError;
async fn decode_from(stream: S) -> Result<Self, Self::Error> {
UnidirectionalStream::accept(stream).await
}
}
impl UnidirectionalStream<()> {
pub const PUSH_STREAM_TYPE: VarInt = VarInt::from_u32(0x01);
}
impl<S: ?Sized> UnidirectionalStream<S> {
pub async fn initial(r#type: VarInt, mut stream: S) -> Result<Self, StreamError>
where
S: AsyncWrite + Unpin + Sized + Send,
{
stream.encode_one(r#type).await?;
Ok(Self { r#type, stream })
}
pub async fn accept(mut stream: S) -> Result<Self, StreamError>
where
S: AsyncRead + Unpin + Sized + Send,
{
let r#type = stream.decode_one::<VarInt>().await.map_err(|error| {
DecodeStreamError::from(error)
.map_decode_error(|error| H3GeneralProtocolError::Decode { source: error }.into())
})?;
Ok(UnidirectionalStream { r#type, stream })
}
pub fn into_inner(self) -> S
where
S: Sized,
{
self.stream
}
pub const fn r#type(&self) -> VarInt {
self.r#type
}
pub const fn is_reserved_stream(&self) -> bool {
(self.r#type().into_inner() >= 0x21)
&& (self.r#type.into_inner() - 0x21).is_multiple_of(0x1f)
}
}
impl<S: GetStreamId + ?Sized> GetStreamId for UnidirectionalStream<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 UnidirectionalStream<S> {
fn poll_stop(
self: Pin<&mut Self>,
cx: &mut Context,
code: VarInt,
) -> Poll<Result<(), quic::StreamError>> {
self.project().stream.poll_stop(cx, code)
}
}
impl<R: AsyncRead + ?Sized> AsyncRead for UnidirectionalStream<R> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
self.project().stream.poll_read(cx, buf)
}
}
impl<R: AsyncBufRead + ?Sized> AsyncBufRead for UnidirectionalStream<R> {
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
self.project().stream.poll_fill_buf(cx)
}
fn consume(self: Pin<&mut Self>, amt: usize) {
self.project().stream.consume(amt);
}
}
impl<S: Stream + ?Sized> Stream for UnidirectionalStream<S> {
type Item = S::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.project().stream.poll_next(cx)
}
}
impl<S: CancelStream + ?Sized> CancelStream for UnidirectionalStream<S> {
fn poll_cancel(
self: Pin<&mut Self>,
cx: &mut Context,
code: VarInt,
) -> Poll<Result<(), quic::StreamError>> {
self.project().stream.poll_cancel(cx, code)
}
}
impl<W: AsyncWrite + ?Sized> AsyncWrite for UnidirectionalStream<W> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
self.project().stream.poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.project().stream.poll_flush(cx)
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.project().stream.poll_shutdown(cx)
}
}
impl<T, S: Sink<T> + ?Sized> Sink<T> for UnidirectionalStream<S> {
type Error = S::Error;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.project().stream.poll_ready(cx)
}
fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
self.project().stream.start_send(item)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.project().stream.poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.project().stream.poll_close(cx)
}
}