pub mod listener;
use std::{
pin::Pin,
task::{Context, Poll}
};
use tokio::{
io::{AsyncRead, AsyncWrite, ReadBuf, Result},
net::TcpStream
};
#[cfg(unix)]
use tokio::net::UnixStream;
#[cfg(feature = "tls")]
use tokio_rustls::server::TlsStream;
#[allow(clippy::large_enum_variant)]
pub enum Stream {
Tcp(TcpStream),
#[cfg(unix)]
Uds(UnixStream),
#[cfg(feature = "tls")]
TlsTcp(TlsStream<TcpStream>)
}
impl Stream {
#[inline]
pub const fn reqflush(&self) -> bool {
match self {
Self::Tcp(_) => false,
#[cfg(unix)]
Self::Uds(_) => false,
#[cfg(feature = "tls")]
Self::TlsTcp(_) => true
}
}
pub fn ciphersuite(&self) -> Option<String> {
match self {
#[cfg(feature = "tls")]
Self::TlsTcp(strm) => {
let (_, conn) = strm.get_ref();
let ciphersuite = conn.negotiated_cipher_suite()?;
Some(format!("{:?}", ciphersuite.suite()))
}
_ => None
}
}
}
macro_rules! delegate_call {
($self:ident.$method:ident($($args:ident),+)) => {
unsafe {
match $self.get_unchecked_mut() {
Self::Tcp(s) => Pin::new_unchecked(s).$method($($args),+),
#[cfg(unix)]
Self::Uds(s) => Pin::new_unchecked(s).$method($($args),+),
#[cfg(feature = "tls")]
Self::TlsTcp(s) => Pin::new_unchecked(s).$method($($args),+),
}
}
}
}
impl AsyncRead for Stream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>
) -> Poll<Result<()>> {
delegate_call!(self.poll_read(cx, buf))
}
}
impl AsyncWrite for Stream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8]
) -> Poll<Result<usize>> {
delegate_call!(self.poll_write(cx, buf))
}
fn poll_flush(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<tokio::io::Result<()>> {
delegate_call!(self.poll_flush(cx))
}
fn poll_shutdown(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<tokio::io::Result<()>> {
delegate_call!(self.poll_shutdown(cx))
}
}