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}