protwrap 0.4.3

Thin protocol wrapper for network applications.
Documentation
//! Helpers for working on the end-points receiving connection requests.

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;


/// Representation of a stream acting as a server end-point (passively
/// established connection).
#[allow(clippy::large_enum_variant)]
pub enum Stream {
  /// TCP-based server stream.
  Tcp(TcpStream),

  /// Unix local domain-based server stream.
  #[cfg(unix)]
  Uds(UnixStream),

  /// TLS, based on TCP, based server stream.
  #[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))
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :