use pin_project_lite::pin_project;
use std::fmt::Debug;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite};
pub trait AsyncAccept {
type Connection: AsyncRead + AsyncWrite;
type Address: Debug;
type Error: std::error::Error;
#[allow(clippy::type_complexity)]
fn poll_accept(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(Self::Connection, Self::Address), Self::Error>>;
}
pin_project! {
struct AcceptGenerator<F, A>
{
accept: A,
#[pin]
current: F,
}
}
impl<Conn, Addr, E, F, A> AsyncAccept for AcceptGenerator<F, A>
where
A: FnMut() -> F,
Conn: AsyncRead + AsyncWrite,
E: std::error::Error,
Addr: Debug,
F: Future<Output = Result<(Conn, Addr), E>>,
{
type Connection = Conn;
type Address = Addr;
type Error = E;
fn poll_accept(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(Self::Connection, Self::Address), Self::Error>> {
let mut this = self.project();
let result = this.current.as_mut().poll(cx);
if result.is_ready() {
let next = (this.accept)();
this.current.set(next);
}
result
}
}
pub fn accept_generator<Acc, Conn, Addr, F, E>(
mut accept_fn: Acc,
) -> impl AsyncAccept<Connection = Conn, Error = E, Address = Addr> + Send
where
Acc: (FnMut() -> F) + Send,
Conn: AsyncRead + AsyncWrite + 'static,
Addr: Debug + 'static,
F: Future<Output = Result<(Conn, Addr), E>> + Send,
E: std::error::Error + 'static,
{
let first_future = (accept_fn)();
AcceptGenerator {
accept: accept_fn,
current: first_future,
}
}
pub trait AsyncListener: AsyncAccept {
fn local_addr(&self) -> Result<Self::Address, Self::Error>;
}