itermacros/lib.rs
1#![doc = include_str!("../README.md")]
2
3/// Use pattern unpack iterator
4///
5/// The expression after the equal sign must implement [`IntoIterator`].\
6/// The final pattern may be followed by a trailing comma.
7///
8/// Use else to handle iterator length mismatch or pattern mismatch
9///
10/// - Use `*name` pattern any elements to [`Vec`],
11/// use [`DoubleEndedIterator`] pattern end elements.
12/// - Use `*name: Type` pattern any elements collect into impl [`FromIterator`].
13/// - Use `*=iter` pattern start and end elements, do not check iter is stopped.
14/// Internally use the given variable name to store iterator for future use.
15/// - Use `**name` like `*name`, but use [`Iterator`]
16///
17/// There may be an internal loop, please use the label to break or continue.
18///
19/// [`FromIterator`]: std::iter::FromIterator
20/// [`Iterator`]: std::iter::Iterator
21/// [`IntoIterator`]: std::iter::IntoIterator
22/// [`DoubleEndedIterator`]: std::iter::DoubleEndedIterator
23/// [`Vec`]: std::vec::Vec
24///
25/// # Examples
26///
27/// Sized iterator
28/// ```
29/// # use itermacros::iunpack;
30/// assert_eq!(iunpack!(a, b, c, d, e = 0..5 => {
31/// (a, b, c, d, e)
32/// } else panic!()), (0, 1, 2, 3, 4));
33///
34/// assert_eq!(iunpack!(a, b, c, d, e = 0..3 => {
35/// panic!()
36/// } else(err) {
37/// err
38/// }), 3); // fail, not enough values
39///
40/// assert_eq!(iunpack!(a, b, c, d, e = 0..7 => {
41/// panic!()
42/// } else(err) {
43/// err
44/// }), 5); // fail, too many values
45/// ```
46///
47/// Any size iterator
48/// ```
49/// # use itermacros::iunpack;
50/// # use std::collections::HashSet;
51/// assert_eq!(iunpack!(a, b, *c, d, e = 0..8 => {
52/// (a, b, c, d, e)
53/// } else panic!()), (0, 1, vec![2, 3, 4, 5], 6, 7));
54///
55/// assert_eq!(iunpack!(a, b, *=c, d, e = 0..8 => {
56/// (a, b, c.collect::<Vec<_>>(), d, e)
57/// } else panic!()), (0, 1, vec![2, 3, 4, 5], 6, 7));
58///
59/// assert_eq!(iunpack!(a, b, *c: HashSet<_>, d, e = 0..8 => {
60/// (a, b, c, d, e)
61/// } else panic!()), (0, 1, HashSet::from([2, 3, 4, 5]), 6, 7));
62///
63/// // use Iterator, is not DoubleEndedIterator
64/// assert_eq!(iunpack!(a, b, **c, d, e = 0..8 => {
65/// (a, b, c, d, e)
66/// } else panic!()), (0, 1, vec![2, 3, 4, 5], 6, 7));
67///
68/// // no collect
69/// assert_eq!(iunpack!(a, b, *, d, e = 0..8 => {
70/// (a, b, d, e)
71/// } else panic!()), (0, 1, 6, 7));
72///
73/// // use Iterator, is not DoubleEndedIterator, no collect
74/// assert_eq!(iunpack!(a, b, **, d, e = 0..8 => {
75/// (a, b, d, e)
76/// } else panic!()), (0, 1, 6, 7));
77/// ```
78///
79/// Pattern example
80/// ```
81/// # use itermacros::iunpack;
82/// # use std::collections::HashSet;
83/// assert_eq!(iunpack!(_a, _b, 2..=10 = 0..3 => { true } else panic!()), true);
84///
85/// assert_eq!(iunpack!((0 | 1 | 2), _b, _c = 0..3 => {
86/// true
87/// } else panic!()), true);
88///
89/// assert_eq!(iunpack!(*, 2..=10 = 0..3 => {
90/// true
91/// } else panic!()), true);
92///
93/// assert_eq!(iunpack!((0 | 1 | 2), * = 0..3 => {
94/// true
95/// } else panic!()), true);
96///
97/// // fails
98/// assert_eq!(iunpack!(_a, _b, 3..=10 = 0..3 => {
99/// panic!()
100/// } else true), true);
101///
102/// assert_eq!(iunpack!((1 | 2), _b, _c = 0..3 => {
103/// panic!()
104/// } else true), true);
105///
106/// assert_eq!(iunpack!(_a, **, 3..=10 = 0..3 => {
107/// panic!()
108/// } else true), true);
109///
110/// assert_eq!(iunpack!((1 | 2), * = 0..3 => {
111/// panic!()
112/// } else true), true);
113/// ```
114#[macro_export]
115macro_rules! iunpack {
116 (@if($($t:tt)*) else $($f:tt)*) => ($($t)*);
117 (@if else $($f:tt)*) => ($($f)*);
118 {@revpat_do_iter_back($iter:ident, $body:block, $errbody:expr)
119 $(($used:pat) $(($pat:pat))*)?
120 } => {
121 $crate::iunpack!(@if$((
122 $crate::iunpack!(
123 @revpat_do_iter_back($iter, {
124 if let ::core::option::Option::Some($used)
125 = ::core::iter::DoubleEndedIterator::next_back(&mut $iter)
126 {
127 $body
128 } else {
129 $errbody
130 }
131 }, $errbody) $(($pat))*
132 )
133 ))? else $body)
134 };
135 {@sized_pat($iter:ident, $body:block, $errbody:block, $errval:ident)
136 $($fpat:pat $(, $pat:pat)*)?
137 } => {
138 $crate::iunpack!(@if$((
139 if let ::core::option::Option::Some($fpat)
140 = ::core::iter::Iterator::next(&mut $iter) {
141 $errval += 1;
142 $crate::iunpack!(@sized_pat(
143 $iter,
144 $body,
145 $errbody,
146 $errval
147 ) $($pat),*)
148 } else $errbody
149 ))? else $body)
150 };
151 {@sized_pat($iter:ident, $body:block, $errbody:block)
152 $($fpat:pat $(, $pat:pat)*)?
153 } => {
154 $crate::iunpack!(@if$((
155 if let ::core::option::Option::Some($fpat)
156 = ::core::iter::Iterator::next(&mut $iter) {
157 $crate::iunpack!(@sized_pat(
158 $iter,
159 $body,
160 $errbody
161 ) $($pat),*)
162 } else $errbody
163 ))? else $body)
164 };
165 // unused err value
166 {
167 $($pat:pat),* $(,)?
168 = $iter:expr => $body:block
169 else $errbody:expr
170 } => {{
171 let mut __iter = ::core::iter::IntoIterator::into_iter($iter);
172 $crate::iunpack!(@sized_pat(__iter, {
173 if let ::core::option::Option::Some(_)
174 = ::core::iter::Iterator::next(&mut __iter) {
175 $errbody
176 } else {
177 $body
178 }
179 }, { $errbody }) $($pat),*)
180 }};
181 // used err value
182 {
183 $($pat:pat),* $(,)?
184 = $iter:expr => $body:block
185 else($err:ident) $errbody:block
186 } => {{
187 let mut __iter = ::core::iter::IntoIterator::into_iter($iter);
188 let mut $err = 0usize;
189 $crate::iunpack!(@sized_pat(__iter, {
190 if let ::core::option::Option::Some(_)
191 = ::core::iter::Iterator::next(&mut __iter) {
192 $errbody
193 } else {
194 $body
195 }
196 }, { $errbody }, $err) $($pat),*)
197 }};
198 // use DoubleEndedIterator
199 {
200 $($fpat:pat ,)* * $($mid:ident $(: $ty:ty)?)? $(, $bpat:pat)* $(,)?
201 = $iter:expr => $body:block
202 else $errbody:expr
203 } => {{
204 let mut __iter = ::core::iter::IntoIterator::into_iter($iter);
205 $crate::iunpack!(@sized_pat(__iter, {
206 $crate::iunpack!(
207 @revpat_do_iter_back(__iter, {
208 $(
209 let $mid = <$crate::iunpack!(
210 @if$(($ty))?else ::std::vec::Vec<_>)
211 as ::core::iter::FromIterator<_>>
212 ::from_iter(__iter);
213 )?
214 $body
215 }, $errbody)
216 $(($bpat))*
217 )
218 }, { $errbody }) $($fpat),*)
219 }};
220 // use DoubleEndedIterator and result mid iterator
221 {
222 $($fpat:pat ,)* *=$mid:ident $(, $bpat:pat)* $(,)?
223 = $iter:expr => $body:block
224 else $errbody:expr
225 } => {{
226 let mut $mid = ::core::iter::IntoIterator::into_iter($iter);
227 $crate::iunpack!(@sized_pat($mid, {
228 $crate::iunpack!(
229 @revpat_do_iter_back($mid, {
230 $body
231 }, $errbody)
232 $(($bpat))*
233 )
234 }, { $errbody }) $($fpat),*)
235 }};
236 // use Iterator unnamed
237 {
238 $($fpat:pat ,)* ** $(, $bpat:pat)+ $(,)?
239 = $iter:expr => $body:block
240 else $errbody:expr
241 } => {loop {
242 let mut __iter = ::core::iter::IntoIterator::into_iter($iter);
243 break $crate::iunpack!(@sized_pat(__iter, {
244 let mut __buf = [$(
245 match ::core::iter::Iterator::next(&mut __iter) {
246 ::core::option::Option::Some(
247 $crate::iunpack!(@if(x) else $bpat)
248 ) => x,
249 ::core::option::Option::None => break $errbody,
250 }
251 ),+];
252 let mut __i = 0;
253 while let ::core::option::Option::Some(__elem)
254 = ::core::iter::Iterator::next(&mut __iter) {
255 __buf[__i] = __elem;
256 __i += 1;
257 __i %= __buf.len();
258 }
259 __buf.rotate_left(__i);
260 #[allow(irrefutable_let_patterns)]
261 if let [$($bpat),+] = __buf {
262 $body
263 } else { $errbody }
264 }, { $errbody }) $($fpat),*)
265 }};
266 // use Iterator
267 {
268 $($fpat:pat ,)* ** $mid:ident $(: $ty:ty)? $(, $bpat:pat)+ $(,)?
269 = $iter:expr => $body:block
270 else $errbody:expr
271 } => {loop {
272 let mut __iter = ::core::iter::IntoIterator::into_iter($iter);
273 break $crate::iunpack!(@sized_pat(__iter, {
274 let mut __buf = [$(
275 match ::core::iter::Iterator::next(&mut __iter) {
276 ::core::option::Option::Some(
277 $crate::iunpack!(@if(x) else $bpat)
278 ) => x,
279 ::core::option::Option::None => break $errbody,
280 }
281 ),+];
282 let mut __i = 0;
283 let mut $mid = <$crate::iunpack!(@if$(($ty))?
284 else ::std::vec::Vec<_>)
285 as ::core::default::Default>::default();
286 while let ::core::option::Option::Some(__elem)
287 = ::core::iter::Iterator::next(&mut __iter) {
288 ::core::iter::Extend::extend(
289 &mut $mid,
290 ::core::option::Option::Some(
291 ::core::mem::replace(&mut __buf[__i], __elem)
292 )
293 );
294 __i += 1;
295 __i %= __buf.len();
296 }
297 __buf.rotate_left(__i);
298 #[allow(irrefutable_let_patterns)]
299 if let [$($bpat),+] = __buf {
300 $body
301 } else { $errbody }
302 }, { $errbody }) $($fpat),*)
303 }};
304}