use std::{
io,
pin::Pin,
task::{Context, Poll},
};
use bytes::Bytes;
use crate::{ReadError, ReadExactError, ReadToEndError, SessionError};
#[derive(Debug)]
pub struct RecvStream {
inner: quinn::RecvStream,
}
impl RecvStream {
pub(crate) fn new(stream: quinn::RecvStream) -> Self {
Self { inner: stream }
}
pub fn stop(&mut self, code: u32) -> Result<(), quinn::ClosedStream> {
let code = webtrans_proto::error_to_http3(code);
let code = quinn::VarInt::try_from(code).unwrap();
self.inner.stop(code)
}
pub async fn read(&mut self, buf: &mut [u8]) -> Result<Option<usize>, ReadError> {
self.inner.read(buf).await.map_err(Into::into)
}
pub async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError> {
self.inner.read_exact(buf).await.map_err(Into::into)
}
pub async fn read_chunk(
&mut self,
max_length: usize,
ordered: bool,
) -> Result<Option<quinn::Chunk>, ReadError> {
self.inner
.read_chunk(max_length, ordered)
.await
.map_err(Into::into)
}
pub async fn read_chunks(&mut self, bufs: &mut [Bytes]) -> Result<Option<usize>, ReadError> {
self.inner.read_chunks(bufs).await.map_err(Into::into)
}
pub async fn read_to_end(&mut self, size_limit: usize) -> Result<Vec<u8>, ReadToEndError> {
self.inner.read_to_end(size_limit).await.map_err(Into::into)
}
pub async fn received_reset(&mut self) -> Result<Option<u32>, SessionError> {
match self.inner.received_reset().await {
Ok(None) => Ok(None),
Ok(Some(code)) => Ok(Some(
webtrans_proto::error_from_http3(code.into_inner()).unwrap(),
)),
Err(quinn::ResetError::ConnectionLost(e)) => Err(e.into()),
Err(quinn::ResetError::ZeroRttRejected) => unreachable!("0-RTT not supported"),
}
}
pub fn quic_id(&self) -> quinn::StreamId {
self.inner.id()
}
}
impl tokio::io::AsyncRead for RecvStream {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut tokio::io::ReadBuf,
) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_read(cx, buf)
}
}
impl webtrans_trait::RecvStream for RecvStream {
type Error = ReadError;
fn stop(&mut self, code: u32) {
Self::stop(self, code).ok();
}
async fn read(&mut self, dst: &mut [u8]) -> Result<Option<usize>, Self::Error> {
self.read(dst).await
}
async fn read_chunk(&mut self, max: usize) -> Result<Option<Bytes>, Self::Error> {
self.read_chunk(max, true)
.await
.map(|r| r.map(|chunk| chunk.bytes))
}
async fn closed(&mut self) -> Result<(), Self::Error> {
self.received_reset().await?;
Ok(())
}
}