I've been busy Rusting. I wanted my futures to be as useful as possible and in the process I came up with an easy to use shortcut which, I believe, is suitable for wider audience. It is a habit I brought from C# to abstract services away behind
interfaces traits to make the code modular. For this to work out I needed my services to be easily shared => immutable reference, but able to take advantage of shared resources => interior mutability, the futures safe to send between threads so they can be part of other futures/async IO => Send and Sync.
- The use case for async-trait improvement: A
MaybeTlsstream hiding the complexity of the async native TLS handshake (aync-native-tls) behind a simple
fn encrypt(&mut self) -> Result<(), io::Error>and the trivial alternative implementation of such a thing with rustls (async-tls).
- The use case for Potential: This SMTP client is reusing the SMTP session/transport to dispatch multiple emails, able to reconnect if necessary, handing out future stream to write e-mail body into and taking only an immutable reference. Used in samotop.
Please do tell me (kindly) if I'm doing something silly. I did consider the implications of using a Mutex in
Potential, possible deadlocks, performance penalty... I also paused to think about relying on
drop() for application logic (the
Lease sends it's item back to the
Potential on drop) and factored in some recovery options and docs. Your thoughts?
Last thing bugging me is that I cannot make a sweet
async fn that returns a static future when taking in &self reference. See the example in Potential. While it is possible to construct such a function without the async sugar, async fns/blocks will capture the
&self reference resulting in a compiler upset over lifetimes. Being able to return
'static futures from
&self would be such a neat completion of the async-trait sugar candy story. I understand that async, and async traits especially, are hard. The async fn is represented by a state machine running the future to completion over the await points which have to capture the state... But a future setup before the await point does not necessarily have to be captured as demonstrated in my example. The very much beloved compiler could perhaps somehow detect the setup and roll it inline without the need to capture everything that enters an async block. Possible?