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.
This commit is contained in:
		
							parent
							
								
									1e0c950004
								
							
						
					
					
						commit
						b07db8462f
					
				@ -21,13 +21,11 @@ pub fn derive_bytes(input: TokenStream) -> TokenStream {
 | 
			
		||||
        .map(|field| field.ident.as_ref().unwrap())
 | 
			
		||||
        .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -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::<LitInt>(&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 ),*
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
@ -22,3 +22,25 @@ where
 | 
			
		||||
        std::any::type_name::<Self>()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[derive(TypeUuid)]
 | 
			
		||||
    #[uuid = "af6466c2-a9f4-11eb-bcbc-0242ac130002"]
 | 
			
		||||
    struct TestDeriveStruct<T>
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<T>
 | 
			
		||||
    where
 | 
			
		||||
        T: Bytes + Send + Sync + 'static,
 | 
			
		||||
    {
 | 
			
		||||
        value: T,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(RenderResources)]
 | 
			
		||||
    #[as_crate(bevy_render)]
 | 
			
		||||
    struct GenericRenderResources<T>
 | 
			
		||||
    where
 | 
			
		||||
        T: RenderResource + Send + Sync + 'static,
 | 
			
		||||
    {
 | 
			
		||||
        resource: T,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Bytes, RenderResource, RenderResources)]
 | 
			
		||||
    #[render_resources(from_self)]
 | 
			
		||||
    #[as_crate(bevy_render)]
 | 
			
		||||
    struct FromSelfGenericRenderResources<T>
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user