derive_more_impl/
into_iterator.rs

1use crate::utils::{
2    add_extra_generic_param, add_extra_where_clauses, SingleFieldData, State,
3};
4use proc_macro2::TokenStream;
5use quote::{quote, ToTokens};
6use syn::{parse::Result, DeriveInput};
7
8/// Provides the hook to expand `#[derive(IntoIterator)]` into an implementation of `IntoIterator`
9pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
10    let state =
11        State::with_field_ignore_and_refs(input, trait_name, "into_iterator".into())?;
12    let SingleFieldData {
13        input_type,
14        info,
15        field_type,
16        member,
17        trait_path,
18        ..
19    } = state.assert_single_enabled_field();
20
21    let mut tokens = TokenStream::new();
22
23    for ref_type in info.ref_types() {
24        let reference = ref_type.reference();
25        let lifetime = ref_type.lifetime();
26        let reference_with_lifetime = ref_type.reference_with_lifetime();
27
28        let generics_impl;
29        let (impl_generics, _, _) = if ref_type.is_ref() {
30            generics_impl = add_extra_generic_param(&input.generics, lifetime.clone());
31            generics_impl.split_for_impl()
32        } else {
33            input.generics.split_for_impl()
34        };
35
36        let generics = add_extra_where_clauses(
37            &input.generics,
38            quote! { where #reference_with_lifetime #field_type: #trait_path },
39        );
40        let (_, ty_generics, where_clause) = generics.split_for_impl();
41
42        let casted_trait = &quote! {
43            <#reference_with_lifetime #field_type as #trait_path>
44        };
45        let into_iterator = quote! {
46            #[automatically_derived]
47            impl #impl_generics #trait_path for #reference_with_lifetime #input_type #ty_generics
48                 #where_clause
49            {
50                type Item = #casted_trait::Item;
51                type IntoIter = #casted_trait::IntoIter;
52
53                #[inline]
54                fn into_iter(self) -> Self::IntoIter {
55                    #casted_trait::into_iter(#reference #member)
56                }
57            }
58        };
59        into_iterator.to_tokens(&mut tokens);
60    }
61    Ok(tokens)
62}