bevy/crates/bevy_asset/macros/src/lib.rs
Christian Hughes 7a72bac779
Fix unused variable warning for simple AssetV2 derives (#9961)
# Objective

Fix #9960 

## Solution

Make the `visit` parameter `_visit` if there are no dependencies.

New `cargo expand` output:
```rust
pub struct Rarity {
    pub name: SharedStr,
    pub color: Color,
}
impl bevy::asset::Asset for Rarity {}
impl bevy::asset::VisitAssetDependencies for Rarity {
    fn visit_dependencies(
        &self,
        _visit: &mut impl FnMut(bevy::asset::UntypedAssetId), // <-- fixed
    ) {}
}
impl bevy::reflect::TypePath for Rarity {
    fn type_path() -> &'static str {
        "myasset::item::Rarity"
    }
    fn short_type_path() -> &'static str {
        "Rarity"
    }
    fn type_ident() -> Option<&'static str> {
        ::core::option::Option::Some("Rarity")
    }
    fn crate_name() -> Option<&'static str> {
        ::core::option::Option::Some(
            "myasset::item".split(':').next().unwrap(),
        )
    }
    fn module_path() -> Option<&'static str> {
        ::core::option::Option::Some("myasset::item")
    }
}
```
2023-09-29 08:08:13 +00:00

84 lines
2.9 KiB
Rust

use bevy_macro_utils::BevyManifest;
use proc_macro::{Span, TokenStream};
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Path};
pub(crate) fn bevy_asset_path() -> syn::Path {
BevyManifest::default().get_path("bevy_asset")
}
const DEPENDENCY_ATTRIBUTE: &str = "dependency";
#[proc_macro_derive(Asset, attributes(dependency))]
pub fn derive_asset(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let bevy_asset_path: Path = bevy_asset_path();
let struct_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
let dependency_visitor = match derive_dependency_visitor_internal(&ast, &bevy_asset_path) {
Ok(dependency_visitor) => dependency_visitor,
Err(err) => return err.into_compile_error().into(),
};
TokenStream::from(quote! {
impl #impl_generics #bevy_asset_path::Asset for #struct_name #type_generics #where_clause { }
#dependency_visitor
})
}
#[proc_macro_derive(VisitAssetDependencies, attributes(dependency))]
pub fn derive_asset_dependency_visitor(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let bevy_asset_path: Path = bevy_asset_path();
match derive_dependency_visitor_internal(&ast, &bevy_asset_path) {
Ok(dependency_visitor) => TokenStream::from(dependency_visitor),
Err(err) => err.into_compile_error().into(),
}
}
fn derive_dependency_visitor_internal(
ast: &DeriveInput,
bevy_asset_path: &Path,
) -> Result<proc_macro2::TokenStream, syn::Error> {
let mut field_visitors = Vec::new();
if let Data::Struct(data_struct) = &ast.data {
for field in &data_struct.fields {
if field
.attrs
.iter()
.any(|a| a.path().is_ident(DEPENDENCY_ATTRIBUTE))
{
if let Some(field_ident) = &field.ident {
field_visitors.push(quote! {
#bevy_asset_path::VisitAssetDependencies::visit_dependencies(&self.#field_ident, visit);
});
}
}
}
} else {
return Err(syn::Error::new(
Span::call_site().into(),
"Asset derive currently only works on structs",
));
}
let struct_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
// prevent unused variable warning in case there are no dependencies
let visit = if field_visitors.is_empty() {
quote! { _visit }
} else {
quote! { visit }
};
Ok(quote! {
impl #impl_generics #bevy_asset_path::VisitAssetDependencies for #struct_name #type_generics #where_clause {
fn visit_dependencies(&self, #visit: &mut impl FnMut(#bevy_asset_path::UntypedAssetId)) {
#(#field_visitors)*
}
}
})
}