use std::{
any::{Any, TypeId},
collections::{HashMap, hash_map::DefaultHasher},
fmt::{self, Debug},
hash::{Hash, Hasher},
ops,
pin::Pin,
sync::Arc,
};
use futures::future::BoxFuture;
use crate::{
codec::{ErasedPeekableBiStream, ErasedPeekableUniStream},
connection::StreamError,
quic::{self, ConnectionError},
};
#[derive(Default)]
pub struct Protocols {
layers: HashMap<TypeId, Arc<dyn Protocol>>,
}
impl Debug for Protocols {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_list();
for layer in self.layers.values() {
f.entry(layer.as_ref());
}
f.finish()
}
}
impl Protocols {
pub fn new() -> Self {
Self::default()
}
pub fn get<L: Any>(&self) -> Option<&L> {
self.layers.get(&TypeId::of::<L>()).map(|layer| {
(layer.as_ref() as &dyn Any)
.downcast_ref()
.expect("TypeId collision for protocol layers, this is a bug")
})
}
pub fn insert<L: Protocol>(&mut self, layer: L) {
self.layers.insert(TypeId::of::<L>(), Arc::new(layer));
}
pub(crate) async fn accept_uni(
&self,
mut stream: ErasedPeekableUniStream,
) -> Result<StreamVerdict<ErasedPeekableUniStream>, StreamError> {
for layer in self.layers.values() {
match layer.accept_uni(stream).await? {
StreamVerdict::Accepted => return Ok(StreamVerdict::Accepted),
StreamVerdict::Passed(mut passed) => {
Pin::new(&mut passed).reset();
stream = passed
}
}
}
Ok(StreamVerdict::Passed(stream))
}
pub(crate) async fn accept_bi(
&self,
mut stream: ErasedPeekableBiStream,
) -> Result<StreamVerdict<ErasedPeekableBiStream>, StreamError> {
for layer in self.layers.values() {
match layer.accept_bi(stream).await? {
StreamVerdict::Accepted => return Ok(StreamVerdict::Accepted),
StreamVerdict::Passed(mut passed) => {
Pin::new(&mut passed.0).reset();
stream = passed
}
}
}
Ok(StreamVerdict::Passed(stream))
}
}
pub trait ProductProtocol<C: quic::Connection>:
Any + Send + Sync + Hash + Eq + fmt::Display + fmt::Debug
{
type Protocol: Protocol;
fn init<'a>(
&'a self,
conn: &'a Arc<C>,
layers: &'a Protocols,
) -> BoxFuture<'a, Result<Self::Protocol, ConnectionError>>;
}
pub(crate) trait InitProtocols<C: quic::Connection>:
Send + Sync + fmt::Display + fmt::Debug
{
fn init_protocols<'a>(
&'a self,
conn: &'a Arc<C>,
layers: &'a mut Protocols,
) -> BoxFuture<'a, Result<(), ConnectionError>>;
}
impl<C: quic::Connection, P: ProductProtocol<C>> InitProtocols<C> for P {
fn init_protocols<'a>(
&'a self,
conn: &'a Arc<C>,
layers: &'a mut Protocols,
) -> BoxFuture<'a, Result<(), ConnectionError>> {
Box::pin(async move {
if layers
.get::<<Self as ProductProtocol<C>>::Protocol>()
.is_some()
{
return Ok(());
}
let layer = ProductProtocol::init(self, conn, layers).await?;
layers.insert(layer);
Ok(())
})
}
}
pub(crate) struct IdentifiedProtocolInitializer<C> {
identity: u64,
init: Box<dyn InitProtocols<C>>,
}
impl<C: quic::Connection> IdentifiedProtocolInitializer<C> {
pub fn new<F: ProductProtocol<C>>(factory: F) -> Self {
let identity = {
let mut hasher = DefaultHasher::new();
TypeId::of::<F>().hash(&mut hasher);
factory.hash(&mut hasher);
hasher.finish()
};
Self {
identity,
init: Box::new(factory),
}
}
}
impl<C> ops::Deref for IdentifiedProtocolInitializer<C> {
type Target = dyn InitProtocols<C>;
fn deref(&self) -> &Self::Target {
&*self.init
}
}
impl<C> Hash for IdentifiedProtocolInitializer<C> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.identity.hash(state);
}
}
impl<C> PartialEq for IdentifiedProtocolInitializer<C> {
fn eq(&self, other: &Self) -> bool {
self.identity == other.identity
}
}
impl<C> Eq for IdentifiedProtocolInitializer<C> {}
impl<C> fmt::Debug for IdentifiedProtocolInitializer<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.init, f)
}
}
impl<C> fmt::Display for IdentifiedProtocolInitializer<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.init, f)
}
}
pub trait Protocol: Any + Send + Sync + Debug {
fn accept_uni<'a>(
&'a self,
stream: ErasedPeekableUniStream,
) -> BoxFuture<'a, Result<StreamVerdict<ErasedPeekableUniStream>, StreamError>>;
fn accept_bi<'a>(
&'a self,
stream: ErasedPeekableBiStream,
) -> BoxFuture<'a, Result<StreamVerdict<ErasedPeekableBiStream>, StreamError>>;
}
#[derive(Debug)]
pub enum StreamVerdict<S> {
Accepted,
Passed(S),
}
#[cfg(all(test, feature = "dquic"))]
mod tests {
use std::sync::Arc;
use futures::future::BoxFuture;
use super::*;
use crate::quic::{self, ConnectionError};
#[derive(Debug)]
struct MockProtocol;
impl Protocol for MockProtocol {
fn accept_uni<'a>(
&'a self,
stream: ErasedPeekableUniStream,
) -> BoxFuture<'a, Result<StreamVerdict<ErasedPeekableUniStream>, StreamError>> {
Box::pin(async move { Ok(StreamVerdict::Passed(stream)) })
}
fn accept_bi<'a>(
&'a self,
stream: ErasedPeekableBiStream,
) -> BoxFuture<'a, Result<StreamVerdict<ErasedPeekableBiStream>, StreamError>> {
Box::pin(async move { Ok(StreamVerdict::Passed(stream)) })
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct MockFactoryFoo(u64);
impl fmt::Display for MockFactoryFoo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MockFactory")
}
}
impl<C: quic::Connection> ProductProtocol<C> for MockFactoryFoo {
type Protocol = MockProtocol;
fn init<'a>(
&'a self,
_: &'a Arc<C>,
_: &'a Protocols,
) -> BoxFuture<'a, Result<Self::Protocol, ConnectionError>> {
unimplemented!("not used in identity tests")
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct MockFactoryBar(u64);
impl fmt::Display for MockFactoryBar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MockFactory2")
}
}
#[derive(Debug)]
struct MockProtocol2;
impl Protocol for MockProtocol2 {
fn accept_uni<'a>(
&'a self,
stream: ErasedPeekableUniStream,
) -> BoxFuture<'a, Result<StreamVerdict<ErasedPeekableUniStream>, StreamError>> {
Box::pin(async move { Ok(StreamVerdict::Passed(stream)) })
}
fn accept_bi<'a>(
&'a self,
stream: ErasedPeekableBiStream,
) -> BoxFuture<'a, Result<StreamVerdict<ErasedPeekableBiStream>, StreamError>> {
Box::pin(async move { Ok(StreamVerdict::Passed(stream)) })
}
}
impl<C: quic::Connection> ProductProtocol<C> for MockFactoryBar {
type Protocol = MockProtocol2;
fn init<'a>(
&'a self,
_: &'a Arc<C>,
_: &'a Protocols,
) -> BoxFuture<'a, Result<Self::Protocol, ConnectionError>> {
unimplemented!("not used in identity tests")
}
}
fn identity<C: quic::Connection, F: ProductProtocol<C>>(
f: F,
) -> IdentifiedProtocolInitializer<C> {
IdentifiedProtocolInitializer::new(f)
}
#[cfg(feature = "dquic")]
type C = dquic::prelude::Connection;
#[cfg(feature = "dquic")]
#[test]
fn identity_hash_same_value_same_hash() {
let a = MockFactoryFoo(42);
let b = MockFactoryFoo(42);
assert_eq!(identity::<C, _>(a), identity::<C, _>(b));
}
#[cfg(feature = "dquic")]
#[test]
fn identity_hash_different_value_different_hash() {
let a = MockFactoryFoo(1);
let b = MockFactoryFoo(2);
assert_ne!(identity::<C, _>(a), identity::<C, _>(b));
}
#[cfg(feature = "dquic")]
#[test]
fn identity_hash_different_type_different_hash() {
let a = MockFactoryFoo(1);
let b = MockFactoryBar(1);
assert_ne!(identity::<C, _>(a), identity::<C, _>(b));
}
}