use std::pin::{pin, Pin};
use futures_util::{AsyncRead, AsyncWrite};
use pin_project::pin_project;
pub mod dialer;
pub mod listener;
pub mod tcp;
pub trait Pipe: AsyncRead + AsyncWrite + Send + Unpin + 'static {
fn shared_secret(&self) -> Option<&[u8]> {
None
}
fn protocol(&self) -> &str;
fn remote_addr(&self) -> Option<&str>;
}
impl Pipe for Box<dyn Pipe> {
fn shared_secret(&self) -> Option<&[u8]> {
(**self).shared_secret()
}
fn protocol(&self) -> &str {
(**self).protocol()
}
fn remote_addr(&self) -> Option<&str> {
(**self).remote_addr()
}
}
#[pin_project(project = EitherPipeProj)]
pub enum EitherPipe<L: Pipe, R: Pipe> {
Left(#[pin] L),
Right(#[pin] R),
}
impl<L: Pipe, R: Pipe> AsyncRead for EitherPipe<L, R> {
fn poll_read(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut [u8],
) -> std::task::Poll<std::io::Result<usize>> {
match self.project() {
EitherPipeProj::Left(l) => l.poll_read(cx, buf),
EitherPipeProj::Right(r) => r.poll_read(cx, buf),
}
}
}
impl<L: Pipe, R: Pipe> AsyncWrite for EitherPipe<L, R> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &[u8],
) -> std::task::Poll<std::io::Result<usize>> {
match self.project() {
EitherPipeProj::Left(l) => l.poll_write(cx, buf),
EitherPipeProj::Right(r) => r.poll_write(cx, buf),
}
}
fn poll_flush(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<std::io::Result<()>> {
match self.project() {
EitherPipeProj::Left(l) => l.poll_flush(cx),
EitherPipeProj::Right(r) => r.poll_flush(cx),
}
}
fn poll_close(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<std::io::Result<()>> {
match self.project() {
EitherPipeProj::Left(l) => l.poll_close(cx),
EitherPipeProj::Right(r) => r.poll_close(cx),
}
}
}
impl<L: Pipe, R: Pipe> Pipe for EitherPipe<L, R> {
fn shared_secret(&self) -> Option<&[u8]> {
match self {
EitherPipe::Left(l) => l.shared_secret(),
EitherPipe::Right(r) => r.shared_secret(),
}
}
fn protocol(&self) -> &str {
match self {
EitherPipe::Left(l) => l.protocol(),
EitherPipe::Right(r) => r.protocol(),
}
}
fn remote_addr(&self) -> Option<&str> {
match self {
EitherPipe::Left(l) => l.remote_addr(),
EitherPipe::Right(r) => r.remote_addr(),
}
}
}