From b07db8462f20fff9f5f6c1af915ad73700b7a264 Mon Sep 17 00:00:00 2001 From: Nathan Ward Date: Sat, 1 May 2021 02:57:20 +0000 Subject: [PATCH] Bevy derives handling generics in impl definitions. (#2044) Fixes #2037 (and then some) Problem: - `TypeUuid`, `RenderResource`, and `Bytes` derive macros did not properly handle generic structs. Solution: - Rework the derive macro implementations to handle the generics. --- crates/bevy_derive/src/bytes.rs | 6 +-- crates/bevy_derive/src/render_resource.rs | 3 +- crates/bevy_derive/src/render_resources.rs | 5 +- .../bevy_reflect_derive/src/type_uuid.rs | 3 +- crates/bevy_reflect/src/type_uuid.rs | 22 +++++++++ .../render_resource/render_resource.rs | 49 +++++++++++++++++++ 6 files changed, 80 insertions(+), 8 deletions(-) diff --git a/crates/bevy_derive/src/bytes.rs b/crates/bevy_derive/src/bytes.rs index a1e1afb0bb..a3469b8c76 100644 --- a/crates/bevy_derive/src/bytes.rs +++ b/crates/bevy_derive/src/bytes.rs @@ -21,13 +21,11 @@ pub fn derive_bytes(input: TokenStream) -> TokenStream { .map(|field| field.ident.as_ref().unwrap()) .collect::>(); - let generics = ast.generics; - let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl(); - let struct_name = &ast.ident; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); TokenStream::from(quote! { - impl #impl_generics #bevy_core_path::Bytes for #struct_name#ty_generics { + impl #impl_generics #bevy_core_path::Bytes for #struct_name #ty_generics #where_clause { fn write_bytes(&self, buffer: &mut [u8]) { let mut offset: usize = 0; #(let byte_len = self.#fields.byte_len(); diff --git a/crates/bevy_derive/src/render_resource.rs b/crates/bevy_derive/src/render_resource.rs index ea6a0b8609..e8c758cc07 100644 --- a/crates/bevy_derive/src/render_resource.rs +++ b/crates/bevy_derive/src/render_resource.rs @@ -11,9 +11,10 @@ pub fn derive_render_resource(input: TokenStream) -> TokenStream { let bevy_asset_path: Path = get_path(&modules.bevy_asset); let bevy_core_path: Path = get_path(&modules.bevy_core); let struct_name = &ast.ident; + let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); TokenStream::from(quote! { - impl #bevy_render_path::renderer::RenderResource for #struct_name { + impl #impl_generics #bevy_render_path::renderer::RenderResource for #struct_name #type_generics #where_clause { fn resource_type(&self) -> Option<#bevy_render_path::renderer::RenderResourceType> { Some(#bevy_render_path::renderer::RenderResourceType::Buffer) } diff --git a/crates/bevy_derive/src/render_resources.rs b/crates/bevy_derive/src/render_resources.rs index a86db961d0..ed9d9e06a9 100644 --- a/crates/bevy_derive/src/render_resources.rs +++ b/crates/bevy_derive/src/render_resources.rs @@ -42,11 +42,12 @@ pub fn derive_render_resources(input: TokenStream) -> TokenStream { attributes }); let struct_name = &ast.ident; + let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); let struct_name_string = struct_name.to_string(); if attributes.from_self { TokenStream::from(quote! { - impl #bevy_render_path::renderer::RenderResources for #struct_name { + impl #impl_generics #bevy_render_path::renderer::RenderResources for #struct_name #type_generics #where_clause { fn render_resources_len(&self) -> usize { 1 } @@ -154,7 +155,7 @@ pub fn derive_render_resources(input: TokenStream) -> TokenStream { #(#render_resource_hints,)* ]; - impl #bevy_render_path::renderer::RenderResources for #struct_name { + impl #impl_generics #bevy_render_path::renderer::RenderResources for #struct_name #type_generics #where_clause { fn render_resources_len(&self) -> usize { #render_resource_count } diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/type_uuid.rs b/crates/bevy_reflect/bevy_reflect_derive/src/type_uuid.rs index 800de584f7..257bafac70 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/type_uuid.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/type_uuid.rs @@ -15,6 +15,7 @@ pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre // Build the trait implementation let name = &ast.ident; + let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); let mut uuid = None; for attribute in ast.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { @@ -53,7 +54,7 @@ pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre .map(|byte_str| syn::parse_str::(&byte_str).unwrap()); let gen = quote! { - impl #bevy_reflect_path::TypeUuid for #name { + impl #impl_generics #bevy_reflect_path::TypeUuid for #name #type_generics #where_clause { const TYPE_UUID: #bevy_reflect_path::Uuid = #bevy_reflect_path::Uuid::from_bytes([ #( #bytes ),* ]); diff --git a/crates/bevy_reflect/src/type_uuid.rs b/crates/bevy_reflect/src/type_uuid.rs index ec71f13639..fe59e91737 100644 --- a/crates/bevy_reflect/src/type_uuid.rs +++ b/crates/bevy_reflect/src/type_uuid.rs @@ -22,3 +22,25 @@ where std::any::type_name::() } } + +#[cfg(test)] +mod test { + use super::*; + + #[derive(TypeUuid)] + #[uuid = "af6466c2-a9f4-11eb-bcbc-0242ac130002"] + struct TestDeriveStruct + where + T: Clone, + { + _value: T, + } + + fn test_impl_type_uuid(_: &impl TypeUuid) {} + + #[test] + fn test_generic_type_uuid_derive() { + let test_struct = TestDeriveStruct { _value: 42 }; + test_impl_type_uuid(&test_struct); + } +} diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource.rs b/crates/bevy_render/src/renderer/render_resource/render_resource.rs index c916716d26..e320f9fcf8 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource.rs @@ -273,3 +273,52 @@ impl RenderResources for bevy_transform::prelude::GlobalTransform { RenderResourceIterator::new(self) } } + +#[cfg(test)] +mod test { + use super::*; + + #[derive(RenderResource, Bytes)] + #[as_crate(bevy_render)] + struct GenericRenderResource + where + T: Bytes + Send + Sync + 'static, + { + value: T, + } + + #[derive(RenderResources)] + #[as_crate(bevy_render)] + struct GenericRenderResources + where + T: RenderResource + Send + Sync + 'static, + { + resource: T, + } + + #[derive(Bytes, RenderResource, RenderResources)] + #[render_resources(from_self)] + #[as_crate(bevy_render)] + struct FromSelfGenericRenderResources + where + T: Bytes + Send + Sync + 'static, + { + value: T, + } + + fn test_impl_render_resource(_: &impl RenderResource) {} + fn test_impl_render_resources(_: &impl RenderResources) {} + + #[test] + fn test_generic_render_resource_derive() { + let resource = GenericRenderResource { value: 42 }; + test_impl_render_resource(&resource); + + let resources = GenericRenderResources { resource }; + test_impl_render_resources(&resources); + + let from_self_resources = FromSelfGenericRenderResources { value: 42 }; + test_impl_render_resource(&from_self_resources); + test_impl_render_resources(&from_self_resources); + } +}