Open
Description
I've been thinking that it would be possible for this crate to provide an API that doesn't use proc macros at all, which has a couple of benefits:
- IDEs will be happier
- Rustfmt will work better (Rustfmt cannot format stream! blocks #68)
The API could look like this:
/// async-stream ///
pub fn stream<T, F, Fut>(f: F) -> impl Stream<Item = T>
where
F: FnOnce(Yielder<T>) -> Fut,
Fut: Future<Output = ()>,
{ /* ... */ }
pub fn try_stream<T, E, F, Fut>(f: F) -> impl Stream<Item = Result<T, E>>
where
F: FnOnce(Yielder<T>) -> Fut,
Fut: Future<Output = Result<(), E>>,
{ /* ... */ }
// This macro will shadow the yielder with a function that borrows from a local.
//
// It will panic if called after the first poll or from a different stream.
#[macro_export]
macro_rules! start_stream {
// $yielder must be of type Yielder<T>
($yielder:ident) => { /* ... */ };
}
/// Usage ///
let stream = async_stream::stream(|yielder| async move {
// Must be called in the first poll, otherwise the stream will panic
start_stream!(yielder);
yielder(1).await;
yielder(2).await;
yielder(3).await;
});
I'm pretty sure this would be sound. Ergonomically, we'd lose the nice for await
and yield
syntax as well as the ability to use ?
in regular streams (although users can always use a try_stream
and then flatten the results if they want something like that), but we'd also gain the ability to specify the type of stream with turbofish syntax. I think it might be nice to support both versions in the library, depending on users' preferences. Any thoughts on the design?
Metadata
Metadata
Assignees
Labels
No labels