Skip to content

Instantly share code, notes, and snippets.

@Arnavion
Created September 8, 2017 03:09
Show Gist options
  • Save Arnavion/2d29e5304e21b3eda6ccb5c861f3de83 to your computer and use it in GitHub Desktop.
Save Arnavion/2d29e5304e21b3eda6ccb5c861f3de83 to your computer and use it in GitHub Desktop.
tiny-async-await

A tiny crate that provides async and await macros to create futures::Futures and futures::Streams.

Code that uses these macros requires #![feature(conservative_impl_trait, generators)]

  • Returning a futures::Future

     #![feature(conservative_impl_trait, generators)]
    
     #[macro_use]
     extern crate tiny_async_await as futures; // This crate re-exports the contents of the futures crate.
    
     fn sum() -> impl ::futures::Future<Item = i32, Error = ()> {
     	async!({
     		// await!(future) returns a `Result`
     		let a = await!(futures::future::ok(5))?;
    
     		let b = await!(futures::future::ok(6))?;
    
     		// Return a `Result` that contains the result of the future
     		Ok(a + b)
     	})
     }
    
     fn main() {
     	use futures::{ Async, Future };
    
     	let mut f = sum();
     	assert_eq!(f.poll(), Ok(Async::Ready(11)));
     }
  • Returning a futures::Stream

     #![feature(conservative_impl_trait, generators)]
    
     #[macro_use]
     extern crate tiny_async_await as futures;
    
     fn numbers() -> impl ::futures::Stream<Item = i32, Error = ()> {
     	async!({
     		let a = await!(futures::future::ok(5))?;
     		// Use `syield!` with a `Result` to yield a `futures::Poll` representing the next item...
     		syield!(Ok(a));
    
     		// ...  or error.
     		syield!(Err(()));
    
     		let b = await!(futures::future::ok(6))?;
     		syield!(Ok(b));
    
     		// Return `Ok(())` to indicate the end of the stream
     		Ok(())
     	})
     }
    
     fn main() {
     	use futures::{ Async, Stream };
    
     	let mut f = numbers();
     	assert_eq!(f.poll(), Ok(Async::Ready(Some(5))));
     	assert_eq!(f.poll(), Err(()));
     	assert_eq!(f.poll(), Ok(Async::Ready(Some(6))));
     	assert_eq!(f.poll(), Ok(Async::Ready(None)));
     }
#![feature(conservative_impl_trait, generators, generator_trait)]
/*!
A tiny crate that provides async and await macros to create `futures::Future`s and `futures::Stream`s.
Code that uses these macros requires `#![feature(conservative_impl_trait, generators)]`
- Returning a `futures::Future`
```rust
#![feature(conservative_impl_trait, generators)]
#[macro_use]
extern crate tiny_async_await as futures; // This crate re-exports the contents of the futures crate.
fn sum() -> impl ::futures::Future<Item = i32, Error = ()> {
async!({
// await!(future) returns a `Result`
let a = await!(futures::future::ok(5))?;
let b = await!(futures::future::ok(6))?;
// Return a `Result` that contains the result of the future
Ok(a + b)
})
}
fn main() {
use futures::{ Async, Future };
let mut f = sum();
assert_eq!(f.poll(), Ok(Async::Ready(11)));
}
```
- Returning a `futures::Stream`
```rust
#![feature(conservative_impl_trait, generators)]
#[macro_use]
extern crate tiny_async_await as futures;
fn numbers() -> impl ::futures::Stream<Item = i32, Error = ()> {
async!({
let a = await!(futures::future::ok(5))?;
// Use `syield!` with a `Result` to yield a `futures::Poll` representing the next item...
syield!(Ok(a));
// ... or error.
syield!(Err(()));
let b = await!(futures::future::ok(6))?;
syield!(Ok(b));
// Return `Ok(())` to indicate the end of the stream
Ok(())
})
}
fn main() {
use futures::{ Async, Stream };
let mut f = numbers();
assert_eq!(f.poll(), Ok(Async::Ready(Some(5))));
assert_eq!(f.poll(), Err(()));
assert_eq!(f.poll(), Ok(Async::Ready(Some(6))));
assert_eq!(f.poll(), Ok(Async::Ready(None)));
}
```
!*/
extern crate futures;
pub use futures::*;
#[macro_export]
macro_rules! async {
($e:expr) => {
$crate::__internal::Wrapper(move || $e)
};
}
#[macro_export]
macro_rules! await {
($e:expr) => {{
let mut f = $e;
loop {
let poll = $crate::Future::poll(&mut f);
match poll {
Ok($crate::Async::Ready(value)) => break Ok(value),
Ok($crate::Async::NotReady) => yield Ok($crate::Async::NotReady),
Err(err) => break Err(err),
}
}
}};
}
#[macro_export]
macro_rules! syield {
($e:expr) => {
yield ::std::result::Result::map($e, |value| $crate::Async::Ready(value))
};
}
pub mod __internal {
use ::futures::{ Async, Future, Poll, Stream };
use ::std::ops::{ Generator, GeneratorState };
pub struct Wrapper<G>(pub G);
impl<G, T, E> Future for Wrapper<G> where G: Generator<Yield = Poll<T, E>, Return = Result<T, E>> {
type Item = T;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.0.resume() {
GeneratorState::Yielded(Ok(Async::NotReady)) => Ok(Async::NotReady),
GeneratorState::Yielded(_) => panic!("Can only yield Async::NotReady from a Future generator"),
GeneratorState::Complete(Ok(value)) => Ok(Async::Ready(value)),
GeneratorState::Complete(Err(err)) => Err(err),
}
}
}
impl<G, T, E> Stream for Wrapper<G> where G: ::std::ops::Generator<Yield = Poll<T, E>, Return = Result<(), E>> {
type Item = T;
type Error = E;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self.0.resume() {
GeneratorState::Yielded(Ok(Async::Ready(value))) => Ok(Async::Ready(Some(value))),
GeneratorState::Yielded(Ok(Async::NotReady)) => Ok(Async::NotReady),
GeneratorState::Yielded(Err(err)) => Err(err),
GeneratorState::Complete(Ok(())) => Ok(Async::Ready(None)),
GeneratorState::Complete(Err(err)) => Err(err),
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment