use crate::utils::{ add_extra_generic_param, add_extra_ty_param_bound_ref, SingleFieldData, State, }; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(IntoIterator)]` into an implementation of `IntoIterator` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_refs( input, trait_name, quote!(::core::iter), String::from("into_iterator"), )?; let SingleFieldData { input_type, info, field_type, member, trait_path, .. } = state.assert_single_enabled_field(); let mut tokens = TokenStream::new(); for ref_type in info.ref_types() { let reference = ref_type.reference(); let lifetime = ref_type.lifetime(); let reference_with_lifetime = ref_type.reference_with_lifetime(); let generics_impl; let generics = add_extra_ty_param_bound_ref(&input.generics, trait_path, ref_type); let (_, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, _, _) = if ref_type.is_ref() { generics_impl = add_extra_generic_param(&generics, lifetime.clone()); generics_impl.split_for_impl() } else { generics.split_for_impl() }; // let generics = add_extra_ty_param_bound(&input.generics, trait_path); let casted_trait = "e!(<#reference_with_lifetime #field_type as #trait_path>); let into_iterator = quote! { impl#impl_generics #trait_path for #reference_with_lifetime #input_type#ty_generics #where_clause { type Item = #casted_trait::Item; type IntoIter = #casted_trait::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { #casted_trait::into_iter(#reference #member) } } }; into_iterator.to_tokens(&mut tokens); } Ok(tokens) }