From d9b371c5413ed5f4bf31f905898019ad6ab10527 Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Tue, 24 Oct 2023 21:04:06 -0400 Subject: [PATCH] Allow deriving Dummy with generic types --- dummy_derive/src/lib.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/dummy_derive/src/lib.rs b/dummy_derive/src/lib.rs index ef0f831..128aac8 100644 --- a/dummy_derive/src/lib.rs +++ b/dummy_derive/src/lib.rs @@ -4,7 +4,7 @@ extern crate quote; #[macro_use] extern crate darling; -use syn::{Ident, Type}; +use syn::{parse_quote, GenericParam, Generics, Ident, Type}; use darling::{ast, FromDeriveInput}; use proc_macro::TokenStream; @@ -44,6 +44,7 @@ struct DummyField { #[darling(attributes(dummy), supports(struct_any, enum_any))] struct Dummy { ident: Ident, + generics: Generics, data: ast::Data, } @@ -52,6 +53,8 @@ pub fn derive_dummy(input: TokenStream) -> TokenStream { let parsed = syn::parse(input).expect("syn::parse ok"); let receiver = Dummy::from_derive_input(&parsed).expect("Dummy::from_derive_input ok"); + let generics = add_trait_bounds(receiver.generics); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let receiver_name = &receiver.ident; let expanded = match receiver.data { darling::ast::Data::Struct(darling::ast::Fields { @@ -61,7 +64,7 @@ pub fn derive_dummy(input: TokenStream) -> TokenStream { }) => match style { ast::Style::Unit => { let impl_dummy = quote! { - impl ::fake::Dummy<::fake::Faker> for #receiver_name { + impl #impl_generics ::fake::Dummy<::fake::Faker> for #receiver_name #ty_generics #where_clause { fn dummy_with_rng(_: &::fake::Faker, rng: &mut R) -> Self { #receiver_name } @@ -73,7 +76,7 @@ pub fn derive_dummy(input: TokenStream) -> TokenStream { let tuple_fields: Vec<_> = fields.iter().map(expose_field).collect(); let impl_dummy = quote! { - impl ::fake::Dummy<::fake::Faker> for #receiver_name { + impl #impl_generics ::fake::Dummy<::fake::Faker> for #receiver_name #ty_generics #where_clause { fn dummy_with_rng(_: &::fake::Faker, rng: &mut R) -> Self { #receiver_name(#(#tuple_fields),*) } @@ -98,7 +101,7 @@ pub fn derive_dummy(input: TokenStream) -> TokenStream { .collect(); let impl_dummy = quote! { - impl ::fake::Dummy<::fake::Faker> for #receiver_name { + impl #impl_generics ::fake::Dummy<::fake::Faker> for #receiver_name #ty_generics #where_clause { fn dummy_with_rng(_: &::fake::Faker, rng: &mut R) -> Self { #(#let_statements)* #receiver_name { @@ -170,7 +173,7 @@ pub fn derive_dummy(input: TokenStream) -> TokenStream { .collect(); let impl_dummy = quote! { - impl ::fake::Dummy<::fake::Faker> for #receiver_name { + impl #impl_generics ::fake::Dummy<::fake::Faker> for #receiver_name #ty_generics #where_clause { fn dummy_with_rng(_: &::fake::Faker, rng: &mut R) -> Self { match rng.gen_range(0..#variant_count) { #(#match_statements)* @@ -185,7 +188,7 @@ pub fn derive_dummy(input: TokenStream) -> TokenStream { impl_dummy } else { let impl_dummy = quote! { - impl ::fake::Dummy<::fake::Faker> for #receiver_name { + impl #impl_generics ::fake::Dummy<::fake::Faker> for #receiver_name #ty_generics #where_clause { fn dummy_with_rng(_: &::fake::Faker, rng: &mut R) -> Self { panic!("can not create an empty enum") } @@ -231,3 +234,14 @@ fn expose_field(f: &DummyField) -> proc_macro2::TokenStream { } } } + +fn add_trait_bounds(mut generics: Generics) -> Generics { + for param in &mut generics.params { + if let GenericParam::Type(ref mut type_param) = *param { + type_param + .bounds + .push(parse_quote!(::fake::Dummy<::fake::Faker>)); + } + } + generics +}