Skip to content
This repository was archived by the owner on Jan 6, 2024. It is now read-only.

implement a trait to abstract over async tls acceptors #7

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ quic = ["rustls/quic"]
[dependencies]
futures-lite = "1.10.1"
webpki = "0.21"
async-tls-acceptor = "0.1.0"

[dependencies.rustls]
version = "0.19"
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -110,6 +110,18 @@ impl TlsAcceptor {
}
}

#[async_tls_acceptor::async_trait]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since TlsAcceptor::accept returns a named future, this is more inefficient than using TlsAcceptor::accept directly. I haven't tried to see if that's possible, but if the trait can provide an API something like the following, it will be efficient enough. (Since Output is already a different type, it is not a problem that the type of Future is different between implementations.)

impl<Input> async_tls_acceptor::Acceptor<Input> for TlsAcceptor
where
    Input: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    type Output = server::TlsStream<Input>;
    type Error = std::io::Error;
    type Future = Accept<Input>;
    fn accept(&self, input: Input) -> Self::Future {
        TlsAcceptor::accept(&self, input)
    }
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this is not possible on stable currently, as it requires GATs in order to express futures like this (for situations in which there is no named future, and the unnamed future is not static):

impl<Input> async_tls_acceptor::Acceptor<Input> for TlsAcceptor
where
    Input: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    type Output = TlsStream<Input>;
    type Error = crate::Error;
    type Future<'a> = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'a>>;

    fn accept<'a>(&'a self, input: Input) -> Self::Future<'a> {
        Box::pin(TlsAcceptor::accept(&self, input))
    }
}

Please correct me if I'm mistaken. Boxing the future doesn't seem like a terribly onerous price to pay until async traits land

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can work around that by making the lifetime a parameter of the trait itself. Hint: https://ytrizja.de/blog/2020/1001_rustiit4r.html

impl<Input> async_tls_acceptor::Acceptor<Input> for TlsAcceptor
where
Input: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
type Output = server::TlsStream<Input>;
type Error = std::io::Error;
async fn accept(&self, input: Input) -> Result<Self::Output, Self::Error> {
TlsAcceptor::accept(&self, input).await
}
}

/// Future returned from `TlsConnector::connect` which will resolve
/// once the connection handshake has finished.
pub struct Connect<IO>(MidHandshake<client::TlsStream<IO>>);