use crate::{Runtime, RuntimeTrait, Transport, UdpTransport, Url};
use std::{
any::Any,
fmt::{self, Debug, Formatter},
future::Future,
io,
net::SocketAddr,
pin::Pin,
sync::Arc,
};
pub trait Connector: Send + Sync + 'static {
type Transport: Transport;
type Runtime: RuntimeTrait;
type Udp: UdpTransport;
fn connect(&self, url: &Url) -> impl Future<Output = io::Result<Self::Transport>> + Send;
fn arced(self) -> ArcedConnector
where
Self: Sized,
{
ArcedConnector(Arc::new(self))
}
fn resolve(
&self,
host: &str,
port: u16,
) -> impl Future<Output = io::Result<Vec<SocketAddr>>> + Send;
fn runtime(&self) -> Self::Runtime;
}
#[derive(Clone)]
pub struct ArcedConnector(Arc<dyn ObjectSafeConnector>);
impl Debug for ArcedConnector {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("ArcedConnector").finish()
}
}
impl ArcedConnector {
#[must_use]
pub fn new(connector: impl Connector) -> Self {
connector.arced()
}
pub fn is<T: Any + 'static>(&self) -> bool {
self.as_any().is::<T>()
}
pub fn downcast_ref<T: Any + 'static>(&self) -> Option<&T> {
self.0.as_any().downcast_ref()
}
pub fn downcast_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
Arc::get_mut(&mut self.0)?.as_mut_any().downcast_mut()
}
pub fn runtime(&self) -> Runtime {
self.0.runtime()
}
}
type ConnectResult<'fut> =
Pin<Box<dyn Future<Output = io::Result<Box<dyn Transport>>> + Send + 'fut>>;
trait ObjectSafeConnector: Send + Sync + 'static {
#[must_use]
fn connect<'connector, 'url, 'fut>(&'connector self, url: &'url Url) -> ConnectResult<'fut>
where
'connector: 'fut,
'url: 'fut,
Self: 'fut;
fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any;
fn runtime(&self) -> Runtime;
fn resolve<'connector, 'host, 'fut>(
&'connector self,
host: &'host str,
port: u16,
) -> Pin<Box<dyn Future<Output = io::Result<Vec<SocketAddr>>> + Send + 'fut>>
where
'connector: 'fut,
'host: 'fut,
Self: 'fut;
}
impl<T: Connector> ObjectSafeConnector for T {
fn connect<'connector, 'url, 'fut>(
&'connector self,
url: &'url Url,
) -> Pin<Box<dyn Future<Output = io::Result<Box<dyn Transport>>> + Send + 'fut>>
where
'connector: 'fut,
'url: 'fut,
Self: 'fut,
{
Box::pin(async move {
Connector::connect(self, url)
.await
.map(|t| Box::new(t) as Box<dyn Transport>)
})
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
fn runtime(&self) -> Runtime {
Connector::runtime(self).into()
}
fn resolve<'connector, 'host, 'fut>(
&'connector self,
host: &'host str,
port: u16,
) -> Pin<Box<dyn Future<Output = io::Result<Vec<SocketAddr>>> + Send + 'fut>>
where
'connector: 'fut,
'host: 'fut,
Self: 'fut,
{
Box::pin(async move { Connector::resolve(self, host, port).await })
}
}
impl Connector for ArcedConnector {
type Runtime = Runtime;
type Transport = Box<dyn Transport>;
type Udp = ();
async fn connect(&self, url: &Url) -> io::Result<Box<dyn Transport>> {
self.0.connect(url).await
}
fn arced(self) -> ArcedConnector {
self
}
fn runtime(&self) -> Self::Runtime {
self.0.runtime()
}
async fn resolve(&self, host: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
self.0.resolve(host, port).await
}
}
pub trait QuicClientConfig<C: Connector>: Send + Sync + 'static {
type Endpoint: crate::QuicEndpoint;
fn bind(&self, addr: SocketAddr, runtime: &C::Runtime) -> io::Result<Self::Endpoint>;
}
trait ObjectSafeQuicClientConfig: Send + Sync + 'static {
fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint>;
}
struct BoundQuicClientConfig<Q, C: Connector> {
config: Q,
runtime: C::Runtime,
}
impl<C: Connector, Q: QuicClientConfig<C>> ObjectSafeQuicClientConfig
for BoundQuicClientConfig<Q, C>
{
fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint> {
let endpoint = self.config.bind(addr, &self.runtime)?;
Ok(crate::ArcedQuicEndpoint::from(endpoint))
}
}
#[derive(Clone)]
pub struct ArcedQuicClientConfig(Arc<dyn ObjectSafeQuicClientConfig>);
impl Debug for ArcedQuicClientConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("ArcedQuicClientConfig").finish()
}
}
impl ArcedQuicClientConfig {
#[must_use]
pub fn new<C: Connector, Q: QuicClientConfig<C>>(connector: &C, config: Q) -> Self {
Self(Arc::new(BoundQuicClientConfig {
runtime: connector.runtime(),
config,
}))
}
pub fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint> {
self.0.bind(addr)
}
}