Skip to main content

iter_enum/
lib.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3/*!
4<!-- Note: Document from sync-markdown-to-rustdoc:start through sync-markdown-to-rustdoc:end
5     is synchronized from README.md. Any changes to that range are not preserved. -->
6<!-- tidy:sync-markdown-to-rustdoc:start -->
7
8\#\[derive(Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, Extend)\] for enums.
9
10## Usage
11
12Add this to your `Cargo.toml`:
13
14```toml
15[dependencies]
16iter-enum = "1"
17```
18
19## Examples
20
21```
22use iter_enum::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, Extend};
23
24#[derive(Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, Extend)]
25enum Either<A, B> {
26    A(A),
27    B(B),
28}
29
30fn foo(x: i32) -> impl Iterator<Item = i32> {
31    if x > 0 {
32        Either::A(x..=0)
33    } else {
34        Either::B(Some(x).into_iter())
35    }
36}
37```
38
39See [auto_enums] crate for how to automate patterns like this.
40
41## Supported traits
42
43- [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/iterator.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/iterator.expanded.rs)
44- [`DoubleEndedIterator`](https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/double_ended_iterator.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/double_ended_iterator.expanded.rs)
45- [`ExactSizeIterator`](https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/exact_size_iterator.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/exact_size_iterator.expanded.rs)
46- [`FusedIterator`](https://doc.rust-lang.org/std/iter/trait.FusedIterator.html) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/fused_iterator.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/fused_iterator.expanded.rs)
47- [`Extend`](https://doc.rust-lang.org/std/iter/trait.Extend.html) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/extend.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/extend.expanded.rs)
48- [`ParallelIterator`](https://docs.rs/rayon/latest/rayon/iter/trait.ParallelIterator.html) (*requires `"rayon"` feature*) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/parallel_iterator.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/parallel_iterator.expanded.rs)
49- [`IndexedParallelIterator`](https://docs.rs/rayon/latest/rayon/iter/trait.IndexedParallelIterator.html) (*requires `"rayon"` feature*) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/indexed_parallel_iterator.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/indexed_parallel_iterator.expanded.rs)
50- [`ParallelExtend`](https://docs.rs/rayon/latest/rayon/iter/trait.ParallelExtend.html) (*requires `"rayon"` feature*) - [example](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/parallel_extend.rs) | [generated code](https://github.com/taiki-e/iter-enum/blob/HEAD/tests/expand/parallel_extend.expanded.rs)
51
52## Optional features
53
54- **`rayon`**
55  - Enable to use `#[derive(ParallelIterator, IndexedParallelIterator, ParallelExtend)]`.
56
57## Related Projects
58
59- [auto_enums]: A library for to allow multiple return types by automatically generated enum.
60- [derive_utils]: A procedural macro helper for easily writing [derives macros][proc-macro-derive] for enums.
61- [io-enum]: \#\[derive(Read, Write, Seek, BufRead)\] for enums.
62
63[auto_enums]: https://github.com/taiki-e/auto_enums
64[derive_utils]: https://github.com/taiki-e/derive_utils
65[io-enum]: https://github.com/taiki-e/io-enum
66[proc-macro-derive]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros
67
68<!-- tidy:sync-markdown-to-rustdoc:end -->
69*/
70
71#![doc(test(
72    no_crate_inject,
73    attr(allow(
74        dead_code,
75        unused_variables,
76        clippy::undocumented_unsafe_blocks,
77        clippy::unused_trait_names,
78    ))
79))]
80#![forbid(unsafe_code)]
81// docs.rs only (cfg is enabled by docs.rs, not build script)
82#![cfg_attr(docsrs, feature(doc_cfg))]
83
84use derive_utils::quick_derive;
85use proc_macro::TokenStream;
86
87#[proc_macro_derive(Iterator)]
88pub fn derive_iterator(input: TokenStream) -> TokenStream {
89    // TODO: Add try_fold once try_trait_v2 is stabilized https://github.com/rust-lang/rust/issues/84277
90    quick_derive! {
91        input,
92        ::core::iter::Iterator,
93        trait Iterator {
94            type Item;
95            #[inline]
96            fn next(&mut self) -> ::core::option::Option<Self::Item>;
97            #[inline]
98            fn size_hint(&self) -> (usize, ::core::option::Option<usize>);
99            #[inline]
100            fn count(self) -> usize;
101            #[inline]
102            fn last(self) -> ::core::option::Option<Self::Item>;
103            #[inline]
104            fn nth(&mut self, n: usize) -> ::core::option::Option<Self::Item>;
105            #[inline]
106            #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
107            fn collect<__U: ::core::iter::FromIterator<Self::Item>>(self) -> __U;
108            #[inline]
109            fn partition<__U, __F>(self, f: __F) -> (__U, __U)
110            where
111                __U: ::core::default::Default + ::core::iter::Extend<Self::Item>,
112                __F: ::core::ops::FnMut(&Self::Item) -> bool;
113
114            // Once try_trait_v2 is stabilized, we can replace these by implementing try_fold.
115            #[inline]
116            fn fold<__U, __F>(self, init: __U, f: __F) -> __U
117            where
118                __F: ::core::ops::FnMut(__U, Self::Item) -> __U;
119            #[inline]
120            fn all<__F>(&mut self, f: __F) -> bool
121            where
122                __F: ::core::ops::FnMut(Self::Item) -> bool;
123            #[inline]
124            fn any<__F>(&mut self, f: __F) -> bool
125            where
126                __F: ::core::ops::FnMut(Self::Item) -> bool;
127            #[inline]
128            fn find<__P>(&mut self, predicate: __P) -> ::core::option::Option<Self::Item>
129            where
130                __P: ::core::ops::FnMut(&Self::Item) -> bool;
131            #[inline]
132            fn find_map<__U, __F>(&mut self, f: __F) -> ::core::option::Option<__U>
133            where
134                __F: ::core::ops::FnMut(Self::Item) -> ::core::option::Option<__U>;
135            #[inline]
136            fn position<__P>(&mut self, predicate: __P) -> ::core::option::Option<usize>
137            where
138                __P: ::core::ops::FnMut(Self::Item) -> bool;
139        }
140    }
141}
142
143#[proc_macro_derive(DoubleEndedIterator)]
144pub fn derive_double_ended_iterator(input: TokenStream) -> TokenStream {
145    // TODO: Add try_rfold once try_trait_v2 is stabilized https://github.com/rust-lang/rust/issues/84277
146    // TODO: Add advance_back_by once stabilized https://github.com/rust-lang/rust/issues/77404
147    quick_derive! {
148        input,
149        ::core::iter::DoubleEndedIterator,
150        <Item>,
151        trait DoubleEndedIterator: ::core::iter::Iterator {
152            #[inline]
153            fn next_back(&mut self) -> ::core::option::Option<Self::Item>;
154            #[inline]
155            fn nth_back(&mut self, n: usize) -> ::core::option::Option<Self::Item>;
156
157            // Once try_trait_v2 is stabilized, we can replace these by implementing try_rfold.
158            #[inline]
159            fn rfold<__U, __F>(self, init: __U, f: __F) -> __U
160            where
161                __F: ::core::ops::FnMut(__U, Self::Item) -> __U;
162            #[inline]
163            fn rfind<__P>(&mut self, predicate: __P) -> ::core::option::Option<Self::Item>
164            where
165                __P: ::core::ops::FnMut(&Self::Item) -> bool;
166        }
167    }
168}
169
170#[proc_macro_derive(ExactSizeIterator)]
171pub fn derive_exact_size_iterator(input: TokenStream) -> TokenStream {
172    // TODO: Add is_empty once stabilized https://github.com/rust-lang/rust/issues/35428
173    quick_derive! {
174        input,
175        ::core::iter::ExactSizeIterator,
176        <Item>,
177        trait ExactSizeIterator: ::core::iter::Iterator {
178            #[inline]
179            fn len(&self) -> usize;
180        }
181    }
182}
183
184#[proc_macro_derive(FusedIterator)]
185pub fn derive_fused_iterator(input: TokenStream) -> TokenStream {
186    quick_derive! {
187        input,
188        ::core::iter::FusedIterator,
189        <Item>,
190        trait FusedIterator: ::core::iter::Iterator {}
191    }
192}
193
194#[proc_macro_derive(Extend)]
195pub fn derive_extend(input: TokenStream) -> TokenStream {
196    // TODO: Add extend_one,extend_reserve once stabilized https://github.com/rust-lang/rust/issues/72631
197    quick_derive! {
198        input,
199        ::core::iter::Extend,
200        trait Extend<__A> {
201            #[inline]
202            fn extend<__T: ::core::iter::IntoIterator<Item = __A>>(&mut self, iter: __T);
203        }
204    }
205}
206
207#[cfg(feature = "rayon")]
208#[proc_macro_derive(ParallelIterator)]
209pub fn derive_parallel_iterator(input: TokenStream) -> TokenStream {
210    quick_derive! {
211        input,
212        ::rayon::iter::ParallelIterator,
213        trait ParallelIterator {
214            type Item;
215            #[inline]
216            fn drive_unindexed<__C>(self, consumer: __C) -> __C::Result
217            where
218                __C: ::rayon::iter::plumbing::UnindexedConsumer<Self::Item>;
219            #[inline]
220            fn opt_len(&self) -> ::core::option::Option<usize>;
221        }
222    }
223}
224
225#[cfg(feature = "rayon")]
226#[proc_macro_derive(IndexedParallelIterator)]
227pub fn derive_indexed_parallel_iterator(input: TokenStream) -> TokenStream {
228    quick_derive! {
229        input,
230        ::rayon::iter::IndexedParallelIterator,
231        <Item>,
232        trait IndexedParallelIterator: ::rayon::iter::ParallelIterator {
233            #[inline]
234            fn drive<__C>(self, consumer: __C) -> __C::Result
235            where
236                __C: ::rayon::iter::plumbing::Consumer<Self::Item>;
237            #[inline]
238            fn len(&self) -> usize;
239            #[inline]
240            fn with_producer<__CB>(self, callback: __CB) -> __CB::Output
241            where
242                __CB: ::rayon::iter::plumbing::ProducerCallback<Self::Item>;
243        }
244    }
245}
246
247#[cfg(feature = "rayon")]
248#[proc_macro_derive(ParallelExtend)]
249pub fn derive_parallel_extend(input: TokenStream) -> TokenStream {
250    quick_derive! {
251        input,
252        ::rayon::iter::ParallelExtend,
253        trait ParallelExtend<__T: ::core::marker::Send> {
254            #[inline]
255            fn par_extend<__I>(&mut self, par_iter: __I)
256            where
257                __I: ::rayon::iter::IntoParallelIterator<Item = __T>;
258        }
259    }
260}