Skip to main content

impl_more/
iter.rs

1/// Implement [`IntoIterator`] by forwarding to a field.
2///
3/// Select one or more modes: `owned` for `Self`, `ref` for `&Self`, and `ref_mut`
4/// for `&mut Self`. Each mode uses the inner type's item and iterator types.
5/// Only the selected modes are implemented. Emitted code supports `no_std`.
6///
7/// # Examples
8///
9/// ```
10/// struct Items<T>(Vec<T>);
11///
12/// impl_more::forward_into_iterator!(<T> in Items<T> => Vec<T>; owned, ref, ref_mut);
13///
14/// let mut items = Items(vec![1, 2]);
15/// for item in &mut items { *item += 1; }
16///
17/// assert_eq!((&items).into_iter().copied().collect::<Vec<_>>(), vec![2, 3]);
18/// assert_eq!(items.into_iter().collect::<Vec<_>>(), vec![2, 3]);
19/// ```
20///
21/// Select a named field with `=> field: InnerType`:
22///
23/// ```
24/// struct Items { values: Vec<u8> }
25///
26/// impl_more::forward_into_iterator!(Items => values: Vec<u8>; ref);
27///
28/// assert_eq!((&Items { values: vec![1] }).into_iter().next(), Some(&1));
29/// ```
30#[macro_export]
31macro_rules! forward_into_iterator {
32    (<$($generic:ident),+> in $this:ty => $field:tt : $inner:ty; $($mode:ident),+ $(,)?) => {
33        $crate::forward_into_iterator!(@modes [$($generic),+] $this => $field: $inner; $($mode),+);
34    };
35    (<$($generic:ident),+> in $this:ty => $inner:ty; $($mode:ident),+ $(,)?) => {
36        $crate::forward_into_iterator!(@modes [$($generic),+] $this => 0: $inner; $($mode),+);
37    };
38    ($this:ty => $field:tt : $inner:ty; $($mode:ident),+ $(,)?) => {
39        $crate::forward_into_iterator!(@modes [] $this => $field: $inner; $($mode),+);
40    };
41    ($this:ty => $inner:ty; $($mode:ident),+ $(,)?) => {
42        $crate::forward_into_iterator!(@modes [] $this => 0: $inner; $($mode),+);
43    };
44    (@modes $generics:tt $this:ty => $field:tt : $inner:ty; $($mode:ident),+) => {
45        $( $crate::forward_into_iterator!(@mode $generics $this => $field: $inner; $mode); )+
46    };
47    (@mode [$($generic:ident),*] $this:ty => $field:tt : $inner:ty; owned) => {
48        impl<$($generic),*> ::core::iter::IntoIterator for $this
49        where
50            $inner: ::core::iter::IntoIterator,
51        {
52            type Item = <$inner as ::core::iter::IntoIterator>::Item;
53            type IntoIter = <$inner as ::core::iter::IntoIterator>::IntoIter;
54
55            fn into_iter(self) -> Self::IntoIter {
56                <$inner as ::core::iter::IntoIterator>::into_iter(self.$field)
57            }
58        }
59    };
60    (@mode [$($generic:ident),*] $this:ty => $field:tt : $inner:ty; ref) => {
61        impl<'__impl_more_iter, $($generic),*> ::core::iter::IntoIterator for &'__impl_more_iter $this
62        where
63            $inner: '__impl_more_iter,
64            &'__impl_more_iter $inner: ::core::iter::IntoIterator,
65        {
66            type Item = <&'__impl_more_iter $inner as ::core::iter::IntoIterator>::Item;
67            type IntoIter = <&'__impl_more_iter $inner as ::core::iter::IntoIterator>::IntoIter;
68
69            fn into_iter(self) -> Self::IntoIter {
70                <&'__impl_more_iter $inner as ::core::iter::IntoIterator>::into_iter(&self.$field)
71            }
72        }
73    };
74    (@mode [$($generic:ident),*] $this:ty => $field:tt : $inner:ty; ref_mut) => {
75        impl<'__impl_more_iter, $($generic),*> ::core::iter::IntoIterator for &'__impl_more_iter mut $this
76        where
77            $inner: '__impl_more_iter,
78            &'__impl_more_iter mut $inner: ::core::iter::IntoIterator,
79        {
80            type Item = <&'__impl_more_iter mut $inner as ::core::iter::IntoIterator>::Item;
81            type IntoIter = <&'__impl_more_iter mut $inner as ::core::iter::IntoIterator>::IntoIter;
82
83            fn into_iter(self) -> Self::IntoIter {
84                <&'__impl_more_iter mut $inner as ::core::iter::IntoIterator>::into_iter(&mut self.$field)
85            }
86        }
87    };
88    (@mode $generics:tt $this:ty => $field:tt : $inner:ty; $mode:ident) => {
89        ::core::compile_error!("expected iteration mode `owned`, `ref`, or `ref_mut`");
90    };
91}
92
93/// Implement [`FromIterator`](core::iter::FromIterator) for a single-field wrapper.
94///
95/// Accept any item type supported by the inner collection's `FromIterator`
96/// implementation. The inner type does not need to implement `IntoIterator`.
97/// Emitted code supports `no_std`.
98///
99/// # Examples
100///
101/// ```
102/// struct Items<T>(Vec<T>);
103///
104/// impl_more::forward_from_iterator!(<T> in Items<T> => Vec<T>);
105///
106/// let items = (1..4).collect::<Items<_>>();
107///
108/// assert_eq!(items.0, vec![1, 2, 3]);
109/// ```
110///
111/// ```
112/// struct Text { value: String }
113///
114/// impl_more::forward_from_iterator!(Text => value: String);
115///
116/// let text = ["hello", " world"].iter().copied().collect::<Text>();
117///
118/// assert_eq!(text.value, "hello world");
119/// ```
120#[macro_export]
121macro_rules! forward_from_iterator {
122    (<$($generic:ident),+> in $this:ty => $field:tt : $inner:ty $(,)?) => {
123        $crate::forward_from_iterator!(@impl [$($generic),+] $this => $field: $inner);
124    };
125    (<$($generic:ident),+> in $this:ty => $inner:ty $(,)?) => {
126        $crate::forward_from_iterator!(@impl [$($generic),+] $this => 0: $inner);
127    };
128    ($this:ty => $field:tt : $inner:ty $(,)?) => {
129        $crate::forward_from_iterator!(@impl [] $this => $field: $inner);
130    };
131    ($this:ty => $inner:ty $(,)?) => {
132        $crate::forward_from_iterator!(@impl [] $this => 0: $inner);
133    };
134    (@impl [$($generic:ident),*] $this:ty => $field:tt : $inner:ty) => {
135        impl<__ImplMoreItem, $($generic),*> ::core::iter::FromIterator<__ImplMoreItem> for $this
136        where
137            $inner: ::core::iter::FromIterator<__ImplMoreItem>,
138        {
139            fn from_iter<__ImplMoreIter: ::core::iter::IntoIterator<Item = __ImplMoreItem>>(iter: __ImplMoreIter) -> Self {
140                Self { $field: <$inner as ::core::iter::FromIterator<__ImplMoreItem>>::from_iter(iter) }
141            }
142        }
143    };
144}
145
146/// Implement [`Extend`] by forwarding to a field.
147///
148/// Accept any item type supported by the inner collection's `Extend`
149/// implementation. Emitted code supports `no_std`.
150///
151/// # Examples
152///
153/// ```
154/// struct Items<T>(Vec<T>);
155///
156/// impl_more::forward_extend!(<T> in Items<T> => Vec<T>);
157///
158/// let mut items = Items(vec![1]);
159/// items.extend([2, 3]);
160///
161/// assert_eq!(items.0, vec![1, 2, 3]);
162/// ```
163///
164/// ```
165/// struct Text { value: String }
166///
167/// impl_more::forward_extend!(Text => value: String);
168///
169/// let mut text = Text { value: String::new() };
170/// text.extend(["hello", " world"]);
171///
172/// assert_eq!(text.value, "hello world");
173/// ```
174#[macro_export]
175macro_rules! forward_extend {
176    (<$($generic:ident),+> in $this:ty => $field:tt : $inner:ty $(,)?) => {
177        $crate::forward_extend!(@impl [$($generic),+] $this => $field: $inner);
178    };
179    (<$($generic:ident),+> in $this:ty => $inner:ty $(,)?) => {
180        $crate::forward_extend!(@impl [$($generic),+] $this => 0: $inner);
181    };
182    ($this:ty => $field:tt : $inner:ty $(,)?) => {
183        $crate::forward_extend!(@impl [] $this => $field: $inner);
184    };
185    ($this:ty => $inner:ty $(,)?) => {
186        $crate::forward_extend!(@impl [] $this => 0: $inner);
187    };
188    (@impl [$($generic:ident),*] $this:ty => $field:tt : $inner:ty) => {
189        impl<__ImplMoreItem, $($generic),*> ::core::iter::Extend<__ImplMoreItem> for $this
190        where
191            $inner: ::core::iter::Extend<__ImplMoreItem>,
192        {
193            fn extend<__ImplMoreIter: ::core::iter::IntoIterator<Item = __ImplMoreItem>>(&mut self, iter: __ImplMoreIter) {
194                <$inner as ::core::iter::Extend<__ImplMoreItem>>::extend(&mut self.$field, iter);
195            }
196        }
197    };
198}
199
200#[cfg(test)]
201mod tests {
202    use alloc::{string::String, vec, vec::Vec};
203
204    struct Items<T>(Vec<T>);
205    crate::forward_into_iterator!(<T> in Items<T> => Vec<T>; owned, ref, ref_mut,);
206    crate::forward_from_iterator!(<T> in Items<T> => Vec<T>,);
207    crate::forward_extend!(<T> in Items<T> => Vec<T>,);
208
209    #[test]
210    fn collect_extend_and_iterate_non_copy_items() {
211        let mut items = IntoIterator::into_iter([String::from("a")]).collect::<Items<_>>();
212        items.extend([String::from("b")]);
213        for item in &mut items {
214            item.push('!');
215        }
216        assert_eq!(
217            (&items).into_iter().map(String::as_str).collect::<Vec<_>>(),
218            ["a!", "b!"]
219        );
220        assert_eq!(items.into_iter().collect::<Vec<_>>(), ["a!", "b!"]);
221    }
222
223    #[test]
224    fn generic_named_field_and_borrowed_items() {
225        struct Named<T> {
226            values: Vec<T>,
227        }
228        crate::forward_into_iterator!(<T> in Named<T> => values: Vec<T>; ref_mut, owned, ref);
229        crate::forward_from_iterator!(<T> in Named<T> => values: Vec<T>);
230        crate::forward_extend!(<T> in Named<T> => values: Vec<T>);
231        let source = vec![String::from("a")];
232        let mut items = source.iter().collect::<Named<_>>();
233        items.extend(source.iter());
234        for item in &mut items {
235            assert_eq!(*item, &source[0]);
236        }
237        assert_eq!((&items).into_iter().count(), 2);
238        assert_eq!(
239            items.into_iter().collect::<Vec<_>>(),
240            [&source[0], &source[0]]
241        );
242    }
243
244    #[test]
245    fn concrete_named_field() {
246        struct Named {
247            values: Vec<u8>,
248        }
249        crate::forward_into_iterator!(Named => values: Vec<u8>; owned, ref, ref_mut);
250        crate::forward_from_iterator!(Named => values: Vec<u8>);
251        crate::forward_extend!(Named => values: Vec<u8>);
252        let mut items = (0..2).collect::<Named>();
253        items.extend([2]);
254        for item in &mut items {
255            *item += 1;
256        }
257        assert_eq!((&items).into_iter().copied().collect::<Vec<_>>(), [1, 2, 3]);
258        assert_eq!(items.into_iter().collect::<Vec<_>>(), [1, 2, 3]);
259    }
260
261    #[test]
262    fn concrete_tuple_and_empty_input() {
263        struct Bytes(Vec<u8>);
264        crate::forward_into_iterator!(Bytes => Vec<u8>; owned, ref, ref_mut);
265        crate::forward_from_iterator!(Bytes => Vec<u8>);
266        crate::forward_extend!(Bytes => Vec<u8>);
267        let mut bytes = core::iter::empty::<u8>().collect::<Bytes>();
268        bytes.extend(core::iter::empty::<u8>());
269        assert_eq!((&bytes).into_iter().next(), None);
270        assert_eq!((&mut bytes).into_iter().next(), None);
271        assert_eq!(bytes.into_iter().next(), None);
272    }
273
274    #[test]
275    fn collection_without_into_iterator_accepts_multiple_item_types() {
276        struct Text(String);
277        crate::forward_from_iterator!(Text => String);
278        crate::forward_extend!(Text => String);
279        let mut text = ['a', 'b'].iter().copied().collect::<Text>();
280        text.extend(["cd", "ef"]);
281        text.extend(['g']);
282        assert_eq!(text.0, "abcdefg");
283        assert_eq!(["ab", "cd"].iter().copied().collect::<Text>().0, "abcd");
284    }
285
286    #[test]
287    fn modes_are_opt_in_and_bounds_apply_to_the_collection() {
288        struct Shared<T>(T);
289        crate::forward_into_iterator!(<T> in Shared<T> => T; ref);
290        static_assertions::assert_not_impl_any!(Shared<Vec<u8>>: IntoIterator);
291        static_assertions::assert_not_impl_any!(&mut Shared<Vec<u8>>: IntoIterator);
292        assert_eq!(
293            (&Shared(vec![1, 2]))
294                .into_iter()
295                .copied()
296                .collect::<Vec<_>>(),
297            [1, 2]
298        );
299
300        struct Owned<T>(T);
301        crate::forward_into_iterator!(<T> in Owned<T> => T; owned);
302        static_assertions::assert_not_impl_any!(&Owned<Vec<u8>>: IntoIterator);
303        static_assertions::assert_not_impl_any!(&mut Owned<Vec<u8>>: IntoIterator);
304        assert_eq!(Owned(0..3).into_iter().sum::<u8>(), 3);
305    }
306}