futures_macro_await/
lib.rs

1#![no_std]
2
3//! An internal helper crate to workaround limitations in the
4//! `use_extern_macros` feature with re-exported Macros 1.0 macros.
5//!
6//! All macros defined here should be imported via [`futures::prelude`] instead.
7
8/// Await a sub-future inside an `#[async]` function.
9///
10/// You should pass an object implementing [`Future`] or [`StableFuture`] to
11/// this macro, it will implicitly `yield` while that future returns
12/// [`Async::Pending`] and evaluate to a [`Result`] containing the result of
13/// that future once complete.
14///
15/// # Examples
16///
17#[cfg_attr(feature = "nightly", doc = "```")]
18#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
19/// #![feature(proc_macro, generators, pin)]
20/// extern crate futures;
21///
22/// use futures::prelude::*;
23/// use futures::future;
24/// use futures::stable::block_on_stable;
25///
26/// #[async]
27/// fn probably_one() -> Result<u32, u32> {
28///     let one = await!(future::ok::<u32, u32>(1))?;
29///     Ok(one)
30/// }
31///
32/// assert_eq!(Ok(1), block_on_stable(probably_one()));
33/// ```
34
35#[macro_export]
36macro_rules! await {
37    ($e:expr) => ({
38        let mut future = $e;
39        let future = &mut future;
40        // The above borrow is necessary to force a borrow across a
41        // yield point, proving that we're currently in an immovable
42        // generator, making the below `PinMut::new_unchecked` call
43        // safe.
44        loop {
45            let poll = ::futures::__rt::in_ctx(|ctx| {
46                let pin = unsafe {
47                    ::futures::__rt::std::mem::PinMut::new_unchecked(future)
48                };
49                ::futures::__rt::StableFuture::poll(pin, ctx)
50            });
51            // Allow for #[feature(never_type)] and Future<Error = !>
52            #[allow(unreachable_code, unreachable_patterns)]
53            match poll {
54                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
55                    break ::futures::__rt::std::result::Result::Ok(e)
56                }
57                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
58                ::futures::__rt::std::result::Result::Err(e) => {
59                    break ::futures::__rt::std::result::Result::Err(e)
60                }
61            }
62            yield ::futures::__rt::Async::Pending
63        }
64    })
65}
66
67/// Await an item from a stream inside an `#[async]` function.
68///
69/// You should pass an object implementing [`Stream`] to this macro, it will
70/// implicitly `yield` while that stream returns [`Async::Pending`] and evaluate
71/// to a [`Result`] containing the next item or error from that stream.
72///
73/// If you want to iterate over all items in a `Stream` you should instead see
74/// the documentation on `#[async] for` in the main `#[async]` documentation.
75///
76/// # Examples
77///
78#[cfg_attr(feature = "nightly", doc = "```")]
79#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
80/// #![feature(proc_macro, generators, pin)]
81/// extern crate futures;
82///
83/// use futures::prelude::*;
84/// use futures::stream;
85/// use futures::stable::block_on_stable;
86///
87/// #[async]
88/// fn eventually_ten() -> Result<u32, u32> {
89///     let mut stream = stream::repeat::<u32, u32>(5);
90///     if let Some(first) = await_item!(stream)? {
91///         if let Some(second) = await_item!(stream)? {
92///             return Ok(first + second);
93///         }
94///     }
95///     Err(0)
96/// }
97///
98/// assert_eq!(Ok(10), block_on_stable(eventually_ten()));
99/// ```
100
101#[macro_export]
102macro_rules! await_item {
103    ($e:expr) => ({
104        loop {
105            let poll = ::futures::__rt::in_ctx(|ctx| ::futures::Stream::poll_next(&mut $e, ctx));
106            // Allow for #[feature(never_type)] and Stream<Error = !>
107            #[allow(unreachable_code, unreachable_patterns)]
108            match poll {
109                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
110                    break ::futures::__rt::std::result::Result::Ok(e)
111                }
112                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
113                ::futures::__rt::std::result::Result::Err(e) => {
114                    break ::futures::__rt::std::result::Result::Err(e)
115                }
116            }
117
118            yield ::futures::__rt::Async::Pending
119        }
120    })
121}
122
123/// Yield an item from an `#[async_stream]` function.
124///
125/// # Examples
126///
127#[cfg_attr(feature = "nightly", doc = "```")]
128#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
129/// #![feature(proc_macro, generators, pin)]
130/// extern crate futures;
131///
132/// use futures::prelude::*;
133/// use futures::stream;
134/// use futures::executor::block_on;
135///
136/// #[async_stream(item = u32)]
137/// fn one_five() -> Result<(), u32> {
138///     stream_yield!(1);
139///     stream_yield!(5);
140///     Ok(())
141/// }
142///
143/// assert_eq!(Ok(vec![1, 5]), block_on(one_five().pin().collect()));
144/// ```
145
146// TODO: This macro needs to use an extra temporary variable because of
147// rust-lang/rust#44197, once that's fixed this should just use $e directly
148// inside the yield expression
149#[macro_export]
150macro_rules! stream_yield {
151    ($e:expr) => ({
152        let e = $e;
153        yield ::futures::__rt::Async::Ready(e)
154    })
155}