Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_scene/macros/src/scene_component.rs
30636 views
1
use bevy_ecs_macro_logic::component::{DeriveComponent, StorageAttribute, StorageTy};
2
use bevy_macro_utils::{fq_std::FQDefault, BevyManifest, PathType};
3
use proc_macro2::TokenStream;
4
use quote::quote;
5
use syn::{
6
parenthesized,
7
parse::{Parse, ParseStream},
8
parse_str,
9
token::Paren,
10
DeriveInput, LitStr, Path,
11
};
12
13
pub(crate) fn derive_scene_component(ast: &mut DeriveInput) -> TokenStream {
14
let mut derive_component = match DeriveComponent::parse(ast, StorageAttribute::Allowed) {
15
Ok(value) => value,
16
Err(e) => return e.into_compile_error(),
17
};
18
19
let (bevy_ecs, bevy_scene) = BevyManifest::shared(|manifest| {
20
(
21
manifest.get_path("bevy_ecs"),
22
manifest.get_path("bevy_scene"),
23
)
24
});
25
26
let scene = match parse_attrs(ast) {
27
Ok(attrs) => attrs,
28
Err(err) => {
29
return err.into_compile_error();
30
}
31
};
32
33
let scene = scene.unwrap_or_default();
34
35
let (scene_impl, props_type) = match scene {
36
Scene::Function(path) => (quote! {#path()}, quote! {()}),
37
Scene::Asset(lit_str) => (
38
quote! {#bevy_scene::CachedSceneAsset::from(#lit_str)},
39
quote! {()},
40
),
41
Scene::FunctionProps { function, props } => (quote! {#function(props)}, quote! {#props}),
42
};
43
44
let struct_name = &ast.ident;
45
let (_, type_generics, _) = &ast.generics.split_for_impl();
46
derive_component.additional_requires.push(quote! {
47
required_components.register_required(|| #bevy_scene::SceneComponentInfo::new::<#struct_name #type_generics>(false));
48
});
49
let component_impl = match derive_component.impl_component(ast, &bevy_ecs, StorageTy::Table) {
50
Ok(value) => value,
51
Err(err) => return err.into_compile_error(),
52
};
53
let struct_name = &ast.ident;
54
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
55
quote! {
56
#component_impl
57
58
impl #impl_generics #bevy_scene::SceneComponent for #struct_name #type_generics #where_clause {
59
type Props = #props_type;
60
fn scene(props: Self::Props) -> impl #bevy_scene::Scene {
61
(
62
#scene_impl,
63
<#bevy_scene::InitTemplate::<<#struct_name #type_generics as #bevy_ecs::template::FromTemplate>::Template> as #FQDefault>::default(),
64
#bevy_scene::template_value(#bevy_scene::SceneComponentInfo::new::<#struct_name #type_generics>(true)),
65
)
66
}
67
}
68
}
69
}
70
71
fn parse_attrs(ast: &DeriveInput) -> syn::Result<Option<Scene>> {
72
let mut scene = None;
73
for attr in &ast.attrs {
74
if attr.path().is_ident("scene") {
75
scene = Some(attr.parse_args::<Scene>()?);
76
}
77
}
78
Ok(scene)
79
}
80
81
/// Parsed scene information
82
pub(crate) enum Scene {
83
Function(Path),
84
FunctionProps { function: Path, props: Path },
85
Asset(LitStr),
86
}
87
88
impl Default for Scene {
89
fn default() -> Self {
90
Scene::Function(default_path())
91
}
92
}
93
94
fn default_path() -> Path {
95
// Self::scene will always parse correctly
96
parse_str::<Path>("Self::scene").unwrap()
97
}
98
99
impl Parse for Scene {
100
fn parse(input: ParseStream) -> syn::Result<Self> {
101
Ok(if input.peek(LitStr) {
102
Scene::Asset(input.parse::<LitStr>()?)
103
} else {
104
let path = input.parse::<Path>()?;
105
if let PathType::Type = PathType::new(&path) {
106
return Ok(Scene::FunctionProps {
107
function: default_path(),
108
props: path,
109
});
110
}
111
112
if input.peek(Paren) {
113
let content;
114
parenthesized!(content in input);
115
let props = content.parse::<Path>()?;
116
Scene::FunctionProps {
117
function: path,
118
props,
119
}
120
} else {
121
Scene::Function(path)
122
}
123
})
124
}
125
}
126
127