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}