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}