use futures::io::{AsyncRead, AsyncWrite};
use std::io;
#[cfg(feature = "tokio-providers")]
use tokio_util::compat::{Compat, TokioAsyncReadCompatExt};
pub trait NetworkProvider: Clone + Send + Sync + 'static {
type TcpStream: AsyncRead + AsyncWrite + Unpin + Send + 'static;
type TcpListener: TcpListenerTrait<TcpStream = Self::TcpStream> + 'static;
fn bind(
&self,
addr: &str,
) -> impl std::future::Future<Output = io::Result<Self::TcpListener>> + Send;
fn connect(
&self,
addr: &str,
) -> impl std::future::Future<Output = io::Result<Self::TcpStream>> + Send;
}
pub trait TcpListenerTrait: Send + Sync + 'static {
type TcpStream: AsyncRead + AsyncWrite + Unpin + Send + 'static;
fn accept(
&self,
) -> impl std::future::Future<Output = io::Result<(Self::TcpStream, String)>> + Send;
fn local_addr(&self) -> io::Result<String>;
}
#[cfg(feature = "tokio-providers")]
#[derive(Debug, Clone, Default)]
pub struct TokioNetworkProvider;
#[cfg(feature = "tokio-providers")]
impl TokioNetworkProvider {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[cfg(feature = "tokio-providers")]
impl NetworkProvider for TokioNetworkProvider {
type TcpStream = Compat<tokio::net::TcpStream>;
type TcpListener = TokioTcpListener;
async fn bind(&self, addr: &str) -> io::Result<Self::TcpListener> {
let listener = tokio::net::TcpListener::bind(addr).await?;
Ok(TokioTcpListener { inner: listener })
}
async fn connect(&self, addr: &str) -> io::Result<Self::TcpStream> {
Ok(tokio::net::TcpStream::connect(addr).await?.compat())
}
}
#[cfg(feature = "tokio-providers")]
#[derive(Debug)]
pub struct TokioTcpListener {
inner: tokio::net::TcpListener,
}
#[cfg(feature = "tokio-providers")]
impl TcpListenerTrait for TokioTcpListener {
type TcpStream = Compat<tokio::net::TcpStream>;
async fn accept(&self) -> io::Result<(Self::TcpStream, String)> {
let (stream, addr) = self.inner.accept().await?;
Ok((stream.compat(), addr.to_string()))
}
fn local_addr(&self) -> io::Result<String> {
Ok(self.inner.local_addr()?.to_string())
}
}