use tokio::io::{AsyncRead, AsyncWrite};
use crate::errors::Error;
use crate::models::{ConnectionID, Message, Role, StreamID, Version};
use crate::protocol::{h1::H1Connection, h2::H2Connection, h3::H3Connection};
#[allow(async_fn_in_trait)]
pub trait Connection {
fn version(&self) -> Version;
fn role(&self) -> Role;
fn id(&self) -> ConnectionID;
fn reusable(&self) -> bool {
true
}
async fn send(&mut self, message: Message) -> Result<(), Error>;
async fn receive(&mut self) -> Result<Message, Error>;
async fn close(&mut self);
}
#[allow(async_fn_in_trait)]
pub trait Stream {
fn id(&self) -> StreamID;
async fn reset(&mut self, code: u64);
}
pub trait Transport: AsyncRead + AsyncWrite + Unpin + Send {}
impl<T: AsyncRead + AsyncWrite + Unpin + Send> Transport for T {}
#[allow(clippy::large_enum_variant)]
pub enum AnyConnection {
H1(H1Connection<Box<dyn Transport>>),
H2(H2Connection<Box<dyn Transport>>),
H3(H3Connection),
}
impl Connection for AnyConnection {
fn version(&self) -> Version {
match self {
Self::H1(connection) => connection.version(),
Self::H2(connection) => connection.version(),
Self::H3(connection) => connection.version(),
}
}
fn role(&self) -> Role {
match self {
Self::H1(connection) => connection.role(),
Self::H2(connection) => connection.role(),
Self::H3(connection) => connection.role(),
}
}
fn id(&self) -> ConnectionID {
match self {
Self::H1(connection) => connection.id(),
Self::H2(connection) => connection.id(),
Self::H3(connection) => connection.id(),
}
}
fn reusable(&self) -> bool {
match self {
Self::H1(connection) => connection.reusable(),
Self::H2(connection) => connection.reusable(),
Self::H3(connection) => connection.reusable(),
}
}
async fn send(&mut self, message: Message) -> Result<(), Error> {
match self {
Self::H1(connection) => connection.send(message).await,
Self::H2(connection) => connection.send(message).await,
Self::H3(connection) => connection.send(message).await,
}
}
async fn receive(&mut self) -> Result<Message, Error> {
match self {
Self::H1(connection) => connection.receive().await,
Self::H2(connection) => connection.receive().await,
Self::H3(connection) => connection.receive().await,
}
}
async fn close(&mut self) {
match self {
Self::H1(connection) => connection.close().await,
Self::H2(connection) => connection.close().await,
Self::H3(connection) => connection.close().await,
}
}
}