1use crate::utils::{
2 add_extra_generic_param, add_extra_ty_param_bound_ref, 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 = State::with_field_ignore_and_refs(
11 input,
12 trait_name,
13 quote!(::core::iter),
14 String::from("into_iterator"),
15 )?;
16 let SingleFieldData {
17 input_type,
18 info,
19 field_type,
20 member,
21 trait_path,
22 ..
23 } = state.assert_single_enabled_field();
24
25 let mut tokens = TokenStream::new();
26
27 for ref_type in info.ref_types() {
28 let reference = ref_type.reference();
29 let lifetime = ref_type.lifetime();
30 let reference_with_lifetime = ref_type.reference_with_lifetime();
31
32 let generics_impl;
33 let generics =
34 add_extra_ty_param_bound_ref(&input.generics, trait_path, ref_type);
35 let (_, ty_generics, where_clause) = generics.split_for_impl();
36 let (impl_generics, _, _) = if ref_type.is_ref() {
37 generics_impl = add_extra_generic_param(&generics, lifetime.clone());
38 generics_impl.split_for_impl()
39 } else {
40 generics.split_for_impl()
41 };
42 // let generics = add_extra_ty_param_bound(&input.generics, trait_path);
43 let casted_trait =
44 &quote!(<#reference_with_lifetime #field_type as #trait_path>);
45 let into_iterator = quote! {
46 impl#impl_generics #trait_path for #reference_with_lifetime #input_type#ty_generics #where_clause
47 {
48 type Item = #casted_trait::Item;
49 type IntoIter = #casted_trait::IntoIter;
50 #[inline]
51 fn into_iter(self) -> Self::IntoIter {
52 #casted_trait::into_iter(#reference #member)
53 }
54 }
55 };
56 into_iterator.to_tokens(&mut tokens);
57 }
58 Ok(tokens)
59}
60