Path: blob/main/crates/bevy_scene/macros/src/scene_component.rs
30636 views
use bevy_ecs_macro_logic::component::{DeriveComponent, StorageAttribute, StorageTy};1use bevy_macro_utils::{fq_std::FQDefault, BevyManifest, PathType};2use proc_macro2::TokenStream;3use quote::quote;4use syn::{5parenthesized,6parse::{Parse, ParseStream},7parse_str,8token::Paren,9DeriveInput, LitStr, Path,10};1112pub(crate) fn derive_scene_component(ast: &mut DeriveInput) -> TokenStream {13let mut derive_component = match DeriveComponent::parse(ast, StorageAttribute::Allowed) {14Ok(value) => value,15Err(e) => return e.into_compile_error(),16};1718let (bevy_ecs, bevy_scene) = BevyManifest::shared(|manifest| {19(20manifest.get_path("bevy_ecs"),21manifest.get_path("bevy_scene"),22)23});2425let scene = match parse_attrs(ast) {26Ok(attrs) => attrs,27Err(err) => {28return err.into_compile_error();29}30};3132let scene = scene.unwrap_or_default();3334let (scene_impl, props_type) = match scene {35Scene::Function(path) => (quote! {#path()}, quote! {()}),36Scene::Asset(lit_str) => (37quote! {#bevy_scene::CachedSceneAsset::from(#lit_str)},38quote! {()},39),40Scene::FunctionProps { function, props } => (quote! {#function(props)}, quote! {#props}),41};4243let struct_name = &ast.ident;44let (_, type_generics, _) = &ast.generics.split_for_impl();45derive_component.additional_requires.push(quote! {46required_components.register_required(|| #bevy_scene::SceneComponentInfo::new::<#struct_name #type_generics>(false));47});48let component_impl = match derive_component.impl_component(ast, &bevy_ecs, StorageTy::Table) {49Ok(value) => value,50Err(err) => return err.into_compile_error(),51};52let struct_name = &ast.ident;53let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();54quote! {55#component_impl5657impl #impl_generics #bevy_scene::SceneComponent for #struct_name #type_generics #where_clause {58type Props = #props_type;59fn scene(props: Self::Props) -> impl #bevy_scene::Scene {60(61#scene_impl,62<#bevy_scene::InitTemplate::<<#struct_name #type_generics as #bevy_ecs::template::FromTemplate>::Template> as #FQDefault>::default(),63#bevy_scene::template_value(#bevy_scene::SceneComponentInfo::new::<#struct_name #type_generics>(true)),64)65}66}67}68}6970fn parse_attrs(ast: &DeriveInput) -> syn::Result<Option<Scene>> {71let mut scene = None;72for attr in &ast.attrs {73if attr.path().is_ident("scene") {74scene = Some(attr.parse_args::<Scene>()?);75}76}77Ok(scene)78}7980/// Parsed scene information81pub(crate) enum Scene {82Function(Path),83FunctionProps { function: Path, props: Path },84Asset(LitStr),85}8687impl Default for Scene {88fn default() -> Self {89Scene::Function(default_path())90}91}9293fn default_path() -> Path {94// Self::scene will always parse correctly95parse_str::<Path>("Self::scene").unwrap()96}9798impl Parse for Scene {99fn parse(input: ParseStream) -> syn::Result<Self> {100Ok(if input.peek(LitStr) {101Scene::Asset(input.parse::<LitStr>()?)102} else {103let path = input.parse::<Path>()?;104if let PathType::Type = PathType::new(&path) {105return Ok(Scene::FunctionProps {106function: default_path(),107props: path,108});109}110111if input.peek(Paren) {112let content;113parenthesized!(content in input);114let props = content.parse::<Path>()?;115Scene::FunctionProps {116function: path,117props,118}119} else {120Scene::Function(path)121}122})123}124}125126127