futures_enum/
lib.rs

1//! \#\[derive(Future, Stream, Sink, AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead)\] for enums.
2//!
3//! # Examples
4//!
5//! ```rust
6//! use futures_enum::*;
7//! use std::future::Future;
8//!
9//! #[derive(Future, Stream, Sink, AsyncRead, AsyncWrite, AsyncSeek, AsyncBufRead)]
10//! enum Either<A, B> {
11//!     A(A),
12//!     B(B),
13//! }
14//!
15//! fn foo(x: i32) -> impl Future<Output = i32> {
16//!     if x < 0 { Either::A(async { 1 }) } else { Either::B(async move { x }) }
17//! }
18//! ```
19//!
20//! futures-enum works well even if the dependency contains only sub-crates such
21//! as `futures-core`, `futures-io`, `futures-sink`, etc.
22//!
23//! See [auto_enums](https://github.com/taiki-e/auto_enums) crate for how to
24//! automate patterns like this.
25//!
26//! # Supported traits
27//!
28//! * [`Future`](https://doc.rust-lang.org/std/future/trait.Future.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/future.md)
29//! * [`Stream`](https://docs.rs/futures/0.3/futures/stream/trait.Stream.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/stream.md)
30//! * [`Sink`](https://docs.rs/futures/0.3/futures/sink/trait.Sink.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/sink.md)
31//! * [`AsyncRead`](https://docs.rs/futures/0.3/futures/io/trait.AsyncRead.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/async_read.md)
32//! * [`AsyncWrite`](https://docs.rs/futures/0.3/futures/io/trait.AsyncWrite.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/async_write.md)
33//! * [`AsyncSeek`](https://docs.rs/futures/0.3/futures/io/trait.AsyncSeek.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/async_seek.md)
34//! * [`AsyncBufRead`](https://docs.rs/futures/0.3/futures/io/trait.AsyncBufRead.html) - [generated code](https://github.com/taiki-e/futures-enum/blob/master/doc/async_buf_read.md)
35
36#![doc(test(
37    no_crate_inject,
38    attr(
39        deny(warnings, rust_2018_idioms, single_use_lifetimes),
40        allow(dead_code, unused_variables)
41    )
42))]
43#![forbid(unsafe_code)]
44#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
45#![warn(clippy::all, clippy::default_trait_access)]
46
47// older compilers require explicit `extern crate`.
48#[allow(unused_extern_crates)]
49extern crate proc_macro;
50
51use derive_utils::{derive_trait, quick_derive};
52use proc_macro::TokenStream;
53use quote::{format_ident, quote};
54use syn::{parse_macro_input, parse_quote, Ident};
55
56fn default_crate_name() -> (Ident, Option<String>) {
57    (format_ident!("futures"), None)
58}
59
60#[cfg(feature = "renamed")]
61fn crate_name(crate_names: &[&str]) -> (Ident, Option<String>) {
62    use find_crate::Manifest;
63
64    let manifest = match Manifest::new().ok() {
65        Some(manifest) => manifest,
66        None => return default_crate_name(),
67    };
68
69    manifest
70        .find2(|name, version| {
71            if name == "futures" {
72                let mut pieces = version.split('.');
73                (|| pieces.next()?.parse().ok())() == Some(3)
74            } else {
75                crate_names.iter().any(|s| *s == name)
76            }
77        })
78        .map_or_else(default_crate_name, |package| {
79            if package.is_original() {
80                (format_ident!("{}", package.name), None)
81            } else {
82                (format_ident!("{}", &package.name), Some(package.original_name().to_owned()))
83            }
84        })
85}
86
87#[cfg(not(feature = "renamed"))]
88fn crate_name(_: &[&str]) -> (Ident, Option<String>) {
89    default_crate_name()
90}
91
92#[proc_macro_derive(Future)]
93pub fn derive_future(input: TokenStream) -> TokenStream {
94    quick_derive! {
95        input,
96        ::core::future::Future,
97        trait Future {
98            type Output;
99            #[inline]
100            fn poll(
101                self: ::core::pin::Pin<&mut Self>,
102                cx: &mut ::core::task::Context<'_>,
103            ) -> ::core::task::Poll<Self::Output>;
104        }
105    }
106}
107
108#[proc_macro_derive(Stream)]
109pub fn derive_stream(input: TokenStream) -> TokenStream {
110    let (crate_, _) = crate_name(&["futures", "futures-util", "futures-core"]);
111
112    derive_trait(
113        &parse_macro_input!(input),
114        parse_quote!(::#crate_::stream::Stream),
115        None,
116        parse_quote! {
117            trait Stream {
118                type Item;
119                #[inline]
120                fn poll_next(
121                    self: ::core::pin::Pin<&mut Self>,
122                    cx: &mut ::core::task::Context<'_>,
123                ) -> ::core::task::Poll<::core::option::Option<Self::Item>>;
124                #[inline]
125                fn size_hint(&self) -> (usize, ::core::option::Option<usize>);
126            }
127        },
128    )
129    .into()
130}
131
132#[proc_macro_derive(Sink)]
133pub fn derive_sink(input: TokenStream) -> TokenStream {
134    let (crate_, original) = crate_name(&["futures", "futures-sink"]);
135    let path = if original.as_ref().map_or(false, |s| s == "futures-sink") {
136        quote!(::#crate_)
137    } else {
138        quote!(::#crate_::sink)
139    };
140
141    derive_trait(&parse_macro_input!(input), parse_quote!(#path::Sink), None, parse_quote! {
142        trait Sink<__Item> {
143            type Error;
144            #[inline]
145            fn poll_ready(
146                self: ::core::pin::Pin<&mut Self>,
147                cx: &mut ::core::task::Context<'_>,
148            ) -> ::core::task::Poll<::core::result::Result<(), Self::Error>>;
149            #[inline]
150            fn start_send(
151                self: ::core::pin::Pin<&mut Self>,
152                item: __Item,
153            ) -> ::core::result::Result<(), Self::Error>;
154            #[inline]
155            fn poll_flush(
156                self: ::core::pin::Pin<&mut Self>,
157                cx: &mut ::core::task::Context<'_>,
158            ) -> ::core::task::Poll<::core::result::Result<(), Self::Error>>;
159            #[inline]
160            fn poll_close(
161                self: ::core::pin::Pin<&mut Self>,
162                cx: &mut ::core::task::Context<'_>,
163            ) -> ::core::task::Poll<::core::result::Result<(), Self::Error>>;
164        }
165    })
166    .into()
167}
168
169#[proc_macro_derive(AsyncRead)]
170pub fn derive_async_read(input: TokenStream) -> TokenStream {
171    let (crate_, original) = crate_name(&["futures", "futures-io"]);
172
173    let path = if original.as_ref().map_or(false, |s| s == "futures-io") {
174        quote!(::#crate_)
175    } else {
176        quote!(::#crate_::io)
177    };
178
179    derive_trait(&parse_macro_input!(input), parse_quote!(#path::AsyncRead), None, parse_quote! {
180        trait AsyncRead {
181            #[inline]
182            fn poll_read(
183                self: ::core::pin::Pin<&mut Self>,
184                cx: &mut ::core::task::Context<'_>,
185                buf: &mut [u8],
186            ) -> ::core::task::Poll<::std::io::Result<usize>>;
187            #[inline]
188            fn poll_read_vectored(
189                self: ::core::pin::Pin<&mut Self>,
190                cx: &mut ::core::task::Context<'_>,
191                bufs: &mut [::std::io::IoSliceMut<'_>],
192            ) -> ::core::task::Poll<::std::io::Result<usize>>;
193        }
194    })
195    .into()
196}
197
198#[proc_macro_derive(AsyncWrite)]
199pub fn derive_async_write(input: TokenStream) -> TokenStream {
200    let (crate_, original) = crate_name(&["futures", "futures-io"]);
201
202    let path = if original.as_ref().map_or(false, |s| s == "futures-io") {
203        quote!(::#crate_)
204    } else {
205        quote!(::#crate_::io)
206    };
207
208    derive_trait(&parse_macro_input!(input), parse_quote!(#path::AsyncWrite), None, parse_quote! {
209        trait AsyncWrite {
210            #[inline]
211            fn poll_write(
212                self: ::core::pin::Pin<&mut Self>,
213                cx: &mut ::core::task::Context<'_>,
214                buf: &[u8],
215            ) -> ::core::task::Poll<::std::io::Result<usize>>;
216            #[inline]
217            fn poll_write_vectored(
218                self: ::core::pin::Pin<&mut Self>,
219                cx: &mut ::core::task::Context<'_>,
220                bufs: &[::std::io::IoSlice<'_>],
221            ) -> ::core::task::Poll<::std::io::Result<usize>>;
222            #[inline]
223            fn poll_flush(
224                self: ::core::pin::Pin<&mut Self>,
225                cx: &mut ::core::task::Context<'_>,
226            ) -> ::core::task::Poll<::std::io::Result<()>>;
227            #[inline]
228            fn poll_close(
229                self: ::core::pin::Pin<&mut Self>,
230                cx: &mut ::core::task::Context<'_>,
231            ) -> ::core::task::Poll<::std::io::Result<()>>;
232        }
233    })
234    .into()
235}
236
237#[proc_macro_derive(AsyncSeek)]
238pub fn derive_async_seek(input: TokenStream) -> TokenStream {
239    let (crate_, original) = crate_name(&["futures", "futures-io"]);
240
241    let path = if original.as_ref().map_or(false, |s| s == "futures-io") {
242        quote!(::#crate_)
243    } else {
244        quote!(::#crate_::io)
245    };
246
247    derive_trait(&parse_macro_input!(input), parse_quote!(#path::AsyncSeek), None, parse_quote! {
248        trait AsyncSeek {
249            #[inline]
250            fn poll_seek(
251                self: ::core::pin::Pin<&mut Self>,
252                cx: &mut ::core::task::Context<'_>,
253                pos: ::std::io::SeekFrom,
254            ) -> ::core::task::Poll<::std::io::Result<u64>>;
255        }
256    })
257    .into()
258}
259
260#[proc_macro_derive(AsyncBufRead)]
261pub fn derive_async_buf_read(input: TokenStream) -> TokenStream {
262    let (crate_, original) = crate_name(&["futures", "futures-io"]);
263
264    let path = if original.as_ref().map_or(false, |s| s == "futures-io") {
265        quote!(::#crate_)
266    } else {
267        quote!(::#crate_::io)
268    };
269
270    derive_trait(
271        &parse_macro_input!(input),
272        parse_quote!(#path::AsyncBufRead),
273        None,
274        parse_quote! {
275            trait AsyncBufRead {
276                #[inline]
277                fn poll_fill_buf<'__a>(
278                    self: ::core::pin::Pin<&'__a mut Self>,
279                    cx: &mut ::core::task::Context<'_>,
280                ) -> ::core::task::Poll<::std::io::Result<&'__a [u8]>>;
281                #[inline]
282                fn consume(self: ::core::pin::Pin<&mut Self>, amt: usize);
283            }
284        },
285    )
286    .into()
287}