use crate::{Server, Transport};
use futures_lite::{AsyncRead, AsyncWrite};
use std::{
fmt::Debug,
future::Future,
io,
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use trillium::Info;
pub trait QuicTransportReceive: AsyncRead {
fn stop(&mut self, code: u64);
}
pub trait QuicTransportSend: AsyncWrite {
fn reset(&mut self, code: u64);
}
pub trait QuicTransportBidi: QuicTransportReceive + QuicTransportSend + Transport {}
pub trait QuicConnectionTrait: Clone + Send + Sync + 'static {
type BidiStream: QuicTransportBidi + Unpin + Send + Sync + 'static;
type RecvStream: QuicTransportReceive + Unpin + Send + Sync + 'static;
type SendStream: QuicTransportSend + Unpin + Send + Sync + 'static;
fn accept_bidi(&self) -> impl Future<Output = io::Result<(u64, Self::BidiStream)>> + Send;
fn accept_uni(&self) -> impl Future<Output = io::Result<(u64, Self::RecvStream)>> + Send;
fn open_uni(&self) -> impl Future<Output = io::Result<(u64, Self::SendStream)>> + Send;
fn open_bidi(&self) -> impl Future<Output = io::Result<(u64, Self::BidiStream)>> + Send;
fn remote_address(&self) -> SocketAddr;
fn close(&self, error_code: u64, reason: &[u8]);
fn send_datagram(&self, data: &[u8]) -> io::Result<()>;
fn recv_datagram<F: FnOnce(&[u8]) + Send>(
&self,
callback: F,
) -> impl Future<Output = io::Result<()>> + Send;
fn max_datagram_size(&self) -> Option<usize>;
}
pub trait QuicConfig<S: Server>: Send + 'static {
type Endpoint: QuicEndpoint;
fn bind(
self,
addr: SocketAddr,
runtime: S::Runtime,
info: &mut Info,
) -> Option<io::Result<Self::Endpoint>>;
}
impl<S: Server> QuicConfig<S> for () {
type Endpoint = ();
fn bind(self, _: SocketAddr, _: S::Runtime, _: &mut Info) -> Option<io::Result<()>> {
None
}
}
pub trait QuicEndpoint: Send + Sync + 'static {
type Connection: QuicConnectionTrait;
fn accept(&self) -> impl Future<Output = Option<Self::Connection>> + Send;
fn connect(
&self,
addr: SocketAddr,
server_name: &str,
) -> impl Future<Output = io::Result<Self::Connection>> + Send;
}
#[derive(Debug, Clone, Copy)]
pub enum NoQuic {}
impl QuicTransportSend for NoQuic {
fn reset(&mut self, _code: u64) {
match *self {}
}
}
impl QuicTransportReceive for NoQuic {
fn stop(&mut self, _code: u64) {
match *self {}
}
}
impl QuicTransportBidi for NoQuic {}
impl QuicConnectionTrait for NoQuic {
type BidiStream = NoQuic;
type RecvStream = NoQuic;
type SendStream = NoQuic;
async fn accept_bidi(&self) -> io::Result<(u64, Self::BidiStream)> {
match *self {}
}
async fn accept_uni(&self) -> io::Result<(u64, Self::RecvStream)> {
match *self {}
}
async fn open_uni(&self) -> io::Result<(u64, Self::SendStream)> {
match *self {}
}
async fn open_bidi(&self) -> io::Result<(u64, Self::BidiStream)> {
match *self {}
}
fn remote_address(&self) -> SocketAddr {
match *self {}
}
fn close(&self, _: u64, _: &[u8]) {
match *self {}
}
fn send_datagram(&self, _: &[u8]) -> io::Result<()> {
match *self {}
}
async fn recv_datagram<F: FnOnce(&[u8]) + Send>(&self, _: F) -> io::Result<()> {
match *self {}
}
fn max_datagram_size(&self) -> Option<usize> {
match *self {}
}
}
impl Transport for NoQuic {}
impl AsyncRead for NoQuic {
fn poll_read(
self: Pin<&mut Self>,
_: &mut Context<'_>,
_: &mut [u8],
) -> Poll<io::Result<usize>> {
match *self.get_mut() {}
}
}
impl AsyncWrite for NoQuic {
fn poll_write(self: Pin<&mut Self>, _: &mut Context<'_>, _: &[u8]) -> Poll<io::Result<usize>> {
match *self.get_mut() {}
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
match *self.get_mut() {}
}
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
match *self.get_mut() {}
}
}
impl QuicEndpoint for () {
type Connection = NoQuic;
async fn accept(&self) -> Option<NoQuic> {
None
}
async fn connect(&self, _: SocketAddr, _: &str) -> io::Result<NoQuic> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"QUIC not configured",
))
}
}
type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub(crate) type BoxedRecvStream = Box<dyn QuicTransportReceive + Unpin + Send + Sync>;
pub(crate) type BoxedSendStream = Box<dyn QuicTransportSend + Unpin + Send + Sync>;
pub(crate) type BoxedBidiStream = Box<dyn QuicTransportBidi + Unpin + Send + Sync>;
type ReceiveDatagramCallback<'a> = Box<dyn FnOnce(&[u8]) + Send + 'a>;
trait ObjectSafeQuicConnection: Send + Sync {
fn accept_bidi(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedBidiStream)>>;
fn accept_uni(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedRecvStream)>>;
fn open_uni(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedSendStream)>>;
fn open_bidi(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedBidiStream)>>;
fn remote_address(&self) -> SocketAddr;
fn close(&self, error_code: u64, reason: &[u8]);
fn send_datagram(&self, data: &[u8]) -> io::Result<()>;
fn recv_datagram<'a>(
&'a self,
callback: ReceiveDatagramCallback<'a>,
) -> BoxedFuture<'a, io::Result<()>>;
fn max_datagram_size(&self) -> Option<usize>;
}
impl<T: QuicConnectionTrait> ObjectSafeQuicConnection for T {
fn accept_bidi(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedBidiStream)>> {
Box::pin(async {
let (id, stream) = QuicConnectionTrait::accept_bidi(self).await?;
Ok((id, Box::new(stream) as BoxedBidiStream))
})
}
fn accept_uni(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedRecvStream)>> {
Box::pin(async {
let (id, stream) = QuicConnectionTrait::accept_uni(self).await?;
Ok((id, Box::new(stream) as BoxedRecvStream))
})
}
fn open_uni(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedSendStream)>> {
Box::pin(async {
let (id, stream) = QuicConnectionTrait::open_uni(self).await?;
Ok((id, Box::new(stream) as BoxedSendStream))
})
}
fn open_bidi(&self) -> BoxedFuture<'_, io::Result<(u64, BoxedBidiStream)>> {
Box::pin(async {
let (id, stream) = QuicConnectionTrait::open_bidi(self).await?;
Ok((id, Box::new(stream) as BoxedBidiStream))
})
}
fn remote_address(&self) -> SocketAddr {
QuicConnectionTrait::remote_address(self)
}
fn close(&self, error_code: u64, reason: &[u8]) {
QuicConnectionTrait::close(self, error_code, reason)
}
fn send_datagram(&self, data: &[u8]) -> io::Result<()> {
QuicConnectionTrait::send_datagram(self, data)
}
fn recv_datagram<'a>(
&'a self,
callback: Box<dyn FnOnce(&[u8]) + Send + 'a>,
) -> BoxedFuture<'a, io::Result<()>> {
Box::pin(QuicConnectionTrait::recv_datagram(self, callback))
}
fn max_datagram_size(&self) -> Option<usize> {
QuicConnectionTrait::max_datagram_size(self)
}
}
#[derive(Clone)]
pub struct QuicConnection(Arc<dyn ObjectSafeQuicConnection>);
impl Debug for QuicConnection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QuicConnection")
.field("peer", &self.remote_address())
.finish_non_exhaustive()
}
}
impl<T: QuicConnectionTrait> From<T> for QuicConnection {
fn from(connection: T) -> Self {
Self(Arc::new(connection))
}
}
impl QuicConnection {
pub async fn accept_bidi(&self) -> io::Result<(u64, BoxedBidiStream)> {
self.0.accept_bidi().await
}
pub async fn accept_uni(&self) -> io::Result<(u64, BoxedRecvStream)> {
self.0.accept_uni().await
}
pub async fn open_uni(&self) -> io::Result<(u64, BoxedSendStream)> {
self.0.open_uni().await
}
pub async fn open_bidi(&self) -> io::Result<(u64, BoxedBidiStream)> {
self.0.open_bidi().await
}
pub fn remote_address(&self) -> SocketAddr {
self.0.remote_address()
}
pub fn close(&self, error_code: u64, reason: &[u8]) {
self.0.close(error_code, reason)
}
pub fn send_datagram(&self, data: &[u8]) -> io::Result<()> {
self.0.send_datagram(data)
}
pub async fn recv_datagram<'a, F: FnOnce(&[u8]) + Send + 'a>(
&'a self,
callback: F,
) -> io::Result<()> {
self.0.recv_datagram(Box::new(callback)).await
}
pub fn max_datagram_size(&self) -> Option<usize> {
self.0.max_datagram_size()
}
}
trait ObjectSafeQuicEndpoint: Send + Sync {
fn accept(&self) -> BoxedFuture<'_, Option<QuicConnection>>;
fn connect<'a>(
&'a self,
addr: SocketAddr,
server_name: &'a str,
) -> BoxedFuture<'a, io::Result<QuicConnection>>;
}
impl<T: QuicEndpoint> ObjectSafeQuicEndpoint for T {
fn accept(&self) -> BoxedFuture<'_, Option<QuicConnection>> {
Box::pin(async { QuicEndpoint::accept(self).await.map(QuicConnection::from) })
}
fn connect<'a>(
&'a self,
addr: SocketAddr,
server_name: &'a str,
) -> BoxedFuture<'a, io::Result<QuicConnection>> {
Box::pin(async move {
QuicEndpoint::connect(self, addr, server_name)
.await
.map(QuicConnection::from)
})
}
}
#[derive(Clone)]
pub struct ArcedQuicEndpoint(Arc<dyn ObjectSafeQuicEndpoint>);
impl Debug for ArcedQuicEndpoint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ArcedQuicEndpoint").finish()
}
}
impl<T: QuicEndpoint> From<T> for ArcedQuicEndpoint {
fn from(endpoint: T) -> Self {
Self(Arc::new(endpoint))
}
}
impl ArcedQuicEndpoint {
pub async fn accept(&self) -> Option<QuicConnection> {
self.0.accept().await
}
pub async fn connect(&self, addr: SocketAddr, server_name: &str) -> io::Result<QuicConnection> {
self.0.connect(addr, server_name).await
}
}