Skip to content

Commit

Permalink
Expose non-impl-Trait iterator return types
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Aug 11, 2024
1 parent 7dc05a5 commit 2955ac5
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 54 deletions.
74 changes: 38 additions & 36 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,42 +105,44 @@ 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 + '_ {
Members {
fields: self.iter(),
index: 0,
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,
}
}
}
}
Expand Down
48 changes: 30 additions & 18 deletions src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,34 +103,46 @@ impl Default for Generics {
}

impl Generics {
/// Iterator over the lifetime parameters in `self.params`.
pub fn lifetimes(&self) -> impl Iterator<Item = &LifetimeParam> {
Lifetimes(self.params.iter())
return_impl_trait! {
/// Iterator over the lifetime parameters in `self.params`.
pub fn lifetimes(&self) -> impl Iterator<Item = &LifetimeParam> [Lifetimes] {
Lifetimes(self.params.iter())
}
}

/// Iterator over the lifetime parameters in `self.params`.
pub fn lifetimes_mut(&mut self) -> impl Iterator<Item = &mut LifetimeParam> {
LifetimesMut(self.params.iter_mut())
return_impl_trait! {
/// Iterator over the lifetime parameters in `self.params`.
pub fn lifetimes_mut(&mut self) -> impl Iterator<Item = &mut LifetimeParam> [LifetimesMut] {
LifetimesMut(self.params.iter_mut())
}
}

/// Iterator over the type parameters in `self.params`.
pub fn type_params(&self) -> impl Iterator<Item = &TypeParam> {
TypeParams(self.params.iter())
return_impl_trait! {
/// Iterator over the type parameters in `self.params`.
pub fn type_params(&self) -> impl Iterator<Item = &TypeParam> [TypeParams] {
TypeParams(self.params.iter())
}
}

/// Iterator over the type parameters in `self.params`.
pub fn type_params_mut(&mut self) -> impl Iterator<Item = &mut TypeParam> {
TypeParamsMut(self.params.iter_mut())
return_impl_trait! {
/// Iterator over the type parameters in `self.params`.
pub fn type_params_mut(&mut self) -> impl Iterator<Item = &mut TypeParam> [TypeParamsMut] {
TypeParamsMut(self.params.iter_mut())
}
}

/// Iterator over the constant parameters in `self.params`.
pub fn const_params(&self) -> impl Iterator<Item = &ConstParam> {
ConstParams(self.params.iter())
return_impl_trait! {
/// Iterator over the constant parameters in `self.params`.
pub fn const_params(&self) -> impl Iterator<Item = &ConstParam> [ConstParams] {
ConstParams(self.params.iter())
}
}

/// Iterator over the constant parameters in `self.params`.
pub fn const_params_mut(&mut self) -> impl Iterator<Item = &mut ConstParam> {
ConstParamsMut(self.params.iter_mut())
return_impl_trait! {
/// Iterator over the constant parameters in `self.params`.
pub fn const_params_mut(&mut self) -> impl Iterator<Item = &mut ConstParam> [ConstParamsMut] {
ConstParamsMut(self.params.iter_mut())
}
}

/// Initializes an empty `where`-clause if there is not one present already.
Expand Down
16 changes: 16 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,19 @@ macro_rules! check_keyword_matches {
(pub pub) => {};
(struct struct) => {};
}

#[cfg(any(feature = "full", feature = "derive"))]
macro_rules! return_impl_trait {
(
$(#[$attr:meta])*
$vis:vis fn $name:ident $args:tt -> $impl_trait:ty [$concrete:ty] $body:block
) => {
#[cfg(not(docsrs))]
$(#[$attr])*
$vis fn $name $args -> $concrete $body

#[cfg(docsrs)]
$(#[$attr])*
$vis fn $name $args -> $impl_trait $body
};
}

0 comments on commit 2955ac5

Please sign in to comment.