Rust syntax is only getting worse
Rust syntax is only getting worse
Posted Sep 27, 2025 18:10 UTC (Sat) by NYKevin (subscriber, #129325)In reply to: Rust syntax is only getting worse by geofft
Parent article: Canceling asynchronous Rust
Re composition with Result: Honestly, I think this concern is exaggerated. Option and Result each provide conversion methods into the other, and it would not be unreasonably difficult to do the same with a custom enum. Once you have a conversion method, composition is straightforward enough.
As for general flexibility, this seems like a place where Rust's return-type dispatch might be useful. Here's how it might be spelled:
use std::convert::Infallible; // TODO: Replace with ! when it is stabilized in some future version of Rust. use std::time::Duration; use tokio::time::error::Elapsed; pub enum Timeout<V, E>{ Ok(V), Err(E), Timeout(Elapsed), } // const wrap needed so that Result<V, Infallible> and V don't // have overlapping impls. Ugly hack, but it should work. pub trait IntoTimeout<V, E, const wrap: bool>{ fn into_timeout(self) -> Timeout<V, E>; } impl<V, E> IntoTimeout<V, E, false> for Result<V, E>{ fn into_timeout(self) -> Timeout<V, E>{ match self { Ok(v) => Timeout::Ok(v), Err(e) => Timeout::Err(e), } } } impl<T> IntoTimeout<T, (), false> for Option<T>{ fn into_timeout(self) -> Timeout<T, ()>{ match self { Some(t) => Timeout::Ok(t), None => Timeout::Err(()), } } } impl<T> IntoTimeout<T, Infallible, true> for T{ fn into_timeout(self) -> Timeout<T, Infallible>{ Timeout::Ok(self) } } pub fn timeout<F, T, V, E, const wrap: bool>(d: Duration, fut: F) -> impl Future<Output=Timeout<V, E>> where F: IntoFuture<Output=T>, T: IntoTimeout<V, E, wrap> { // Ugly hack to work around ! not implementing Future. // But this is just placeholder code anyway. std::future::ready(todo!()) }
Clients can implement IntoTimeout if they want to return some exotic thing and convert it into a timeout result. Otherwise, the impls shown above should cover all reasonable cases.
Minor caveat: The real Timeout type is itself a Future, which timeout() returns directly. I did not want to bother actually showing how to implement a Future since it is irrelevant, so I repurposed the name Timeout for the final result type and hid the Future's name behind return-position impl trait. In a proper API, it is usually preferable to give a name to the type you return rather than hiding it in this way, at least in most cases.