Skip to content

Commit

Permalink
Merge pull request #1719 from dtolnay/iterators
Browse files Browse the repository at this point in the history
Expose non-impl-Trait iterator return types
  • Loading branch information
dtolnay committed Aug 11, 2024
2 parents b5a5a8c + 2955ac5 commit 6cf2344
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 194 deletions.
146 changes: 74 additions & 72 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,80 +105,45 @@ impl Fields {
}
}

/// Get an iterator over the fields of a struct or variant as [`Member`]s.
/// This iterator can be used to iterate over a named or unnamed struct or
/// variant's fields uniformly.
///
/// # Example
///
/// The following is a simplistic [`Clone`] derive for structs. (A more
/// complete implementation would additionally want to infer trait bounds on
/// the generic type parameters.)
///
/// ```
/// # use quote::quote;
/// #
/// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
/// let ident = &input.ident;
/// let members = input.fields.members();
/// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
/// quote! {
/// impl #impl_generics Clone for #ident #ty_generics #where_clause {
/// fn clone(&self) -> Self {
/// Self {
/// #(#members: self.#members.clone()),*
/// }
/// }
/// }
/// }
/// }
/// ```
///
/// For structs with named fields, it produces an expression like `Self { a:
/// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
/// self.0.clone() }`. And for unit structs, `Self {}`.
pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ {
struct Members<'a> {
fields: punctuated::Iter<'a, Field>,
index: u32,
}

impl<'a> Iterator for Members<'a> {
type Item = Member;

fn next(&mut self) -> Option<Self::Item> {
let field = self.fields.next()?;
let member = match &field.ident {
Some(ident) => Member::Named(ident.clone()),
None => {
#[cfg(all(feature = "parsing", feature = "printing"))]
let span = crate::spanned::Spanned::span(&field.ty);
#[cfg(not(all(feature = "parsing", feature = "printing")))]
let span = proc_macro2::Span::call_site();
Member::Unnamed(Index {
index: self.index,
span,
})
}
};
self.index += 1;
Some(member)
}
}

impl<'a> Clone for Members<'a> {
fn clone(&self) -> Self {
Members {
fields: self.fields.clone(),
index: self.index,
}
return_impl_trait! {
/// Get an iterator over the fields of a struct or variant as [`Member`]s.
/// This iterator can be used to iterate over a named or unnamed struct or
/// variant's fields uniformly.
///
/// # Example
///
/// The following is a simplistic [`Clone`] derive for structs. (A more
/// complete implementation would additionally want to infer trait bounds on
/// the generic type parameters.)
///
/// ```
/// # use quote::quote;
/// #
/// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
/// let ident = &input.ident;
/// let members = input.fields.members();
/// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
/// quote! {
/// impl #impl_generics Clone for #ident #ty_generics #where_clause {
/// fn clone(&self) -> Self {
/// Self {
/// #(#members: self.#members.clone()),*
/// }
/// }
/// }
/// }
/// }
/// ```
///
/// For structs with named fields, it produces an expression like `Self { a:
/// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
/// self.0.clone() }`. And for unit structs, `Self {}`.
pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] {
Members {
fields: self.iter(),
index: 0,
}
}

Members {
fields: self.iter(),
index: 0,
}
}
}

Expand Down Expand Up @@ -234,6 +199,43 @@ ast_struct! {
}
}

pub struct Members<'a> {
fields: punctuated::Iter<'a, Field>,
index: u32,
}

impl<'a> Iterator for Members<'a> {
type Item = Member;

fn next(&mut self) -> Option<Self::Item> {
let field = self.fields.next()?;
let member = match &field.ident {
Some(ident) => Member::Named(ident.clone()),
None => {
#[cfg(all(feature = "parsing", feature = "printing"))]
let span = crate::spanned::Spanned::span(&field.ty);
#[cfg(not(all(feature = "parsing", feature = "printing")))]
let span = proc_macro2::Span::call_site();
Member::Unnamed(Index {
index: self.index,
span,
})
}
};
self.index += 1;
Some(member)
}
}

impl<'a> Clone for Members<'a> {
fn clone(&self) -> Self {
Members {
fields: self.fields.clone(),
index: self.index,
}
}
}

#[cfg(feature = "parsing")]
pub(crate) mod parsing {
use crate::attr::Attribute;
Expand Down
Loading

0 comments on commit 6cf2344

Please sign in to comment.