Skip to content

Commit 21681d7

Browse files
committed
first pass docs
1 parent 7a55f39 commit 21681d7

File tree

5 files changed

+181
-129
lines changed

5 files changed

+181
-129
lines changed

crates/bevy_reflect/bevy_reflect_derive/src/derive_data.rs

Lines changed: 17 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::field_attributes::{parse_field_attrs, ReflectFieldAttr};
33
use crate::type_path::parse_path_no_leading_colon;
44
use crate::utility::members_to_serialization_denylist;
55
use bit_set::BitSet;
6-
use quote::{quote, ToTokens};
6+
use quote::{quote, ToTokens, TokenStreamExt};
77

88
use crate::{
99
utility, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME,
@@ -225,7 +225,7 @@ impl<'a> ReflectDerive<'a> {
225225
}
226226

227227
let path_to_type = PathToType::Internal {
228-
ident: &input.ident,
228+
name: &input.ident,
229229
alias: alias_type_path,
230230
};
231231

@@ -474,23 +474,27 @@ impl<'a> ReflectEnum<'a> {
474474
}
475475
}
476476

477+
/// Represents a path to a type.
477478
pub(crate) enum PathToType<'a> {
478-
/// Types without a crate/module (e.g. `bool`).
479+
/// Types without a crate/module that can be named from any scope (e.g. `bool`).
479480
Primitive(&'a Ident),
480481
/// Using `::my_crate::foo::Bar` syntax.
481482
///
482483
/// May have a seperate alias path used for the `TypePath` implementation.
483484
External { path: &'a Path, alias: Option<Path> },
484-
/// The name of a type relative to itself.
485-
/// Module and crate are found with [`module_path!()`](core::module_path).
485+
/// The name of a type relative to its scope.
486+
/// The type must be able to be named from just its name.
486487
///
487488
/// May have a seperate alias path used for the `TypePath` implementation.
489+
///
490+
/// Module and crate are found with [`module_path!()`](core::module_path),
491+
/// if there is no alias specified.
488492
Internal {
489-
ident: &'a Ident,
493+
name: &'a Ident,
490494
alias: Option<Path>,
491495
},
492496
/// Any [`syn::Type`] with only a defined `type_path` and `short_type_path`.
493-
#[allow(dead_code)]
497+
#[allow(dead_code)] // Not currently used but may be useful in the future due to its generality.
494498
Anonymous {
495499
qualified_type: Type,
496500
long_type_path: proc_macro2::TokenStream,
@@ -500,10 +504,10 @@ pub(crate) enum PathToType<'a> {
500504

501505
impl<'a> PathToType<'a> {
502506
/// Returns the path interpreted as an [`Ident`],
503-
/// or [`None`] if anonymous.
507+
/// or [`None`] if anonymous or primitive.
504508
fn named_as_ident(&self) -> Option<&Ident> {
505509
match self {
506-
Self::Internal { ident, alias } => Some(
510+
Self::Internal { name: ident, alias } => Some(
507511
alias
508512
.as_ref()
509513
.map(|path| &path.segments.last().unwrap().ident)
@@ -523,7 +527,7 @@ impl<'a> PathToType<'a> {
523527
}
524528

525529
/// Returns the path interpreted as a [`Path`],
526-
/// or [`None`] if anonymous or a non-aliased [`PathToType::Internal`].
530+
/// or [`None`] if anonymous, primitive, or a non-aliased [`PathToType::Internal`].
527531
fn named_as_path(&self) -> Option<&Path> {
528532
match self {
529533
Self::Internal { alias, .. } => alias.as_ref(),
@@ -536,7 +540,7 @@ impl<'a> PathToType<'a> {
536540
///
537541
/// [internal]: PathToType::Internal
538542
/// [external]: PathToType::External
539-
pub fn is_alias(&self) -> bool {
543+
pub fn is_aliased(&self) -> bool {
540544
match self {
541545
Self::Internal { alias, .. } => alias.is_some(),
542546
Self::External { alias, .. } => alias.is_some(),
@@ -635,93 +639,9 @@ impl<'a> PathToType<'a> {
635639
impl<'a> ToTokens for PathToType<'a> {
636640
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
637641
match self {
638-
Self::Internal { ident, .. } | Self::Primitive(ident) => ident.to_tokens(tokens),
642+
Self::Internal { name: ident, .. } | Self::Primitive(ident) => ident.to_tokens(tokens),
639643
Self::External { path, .. } => path.to_tokens(tokens),
640644
Self::Anonymous { qualified_type, .. } => qualified_type.to_tokens(tokens),
641645
}
642646
}
643-
}
644-
645-
pub(crate) fn type_path_generator(meta: &ReflectMeta) -> proc_macro2::TokenStream {
646-
let path_to_type = meta.path_to_type();
647-
let generics = meta.generics();
648-
let bevy_reflect_path = meta.bevy_reflect_path();
649-
// Whether to use `GenericTypedCell` is not dependent on lifetimes
650-
// (which all have to be 'static anyway).
651-
let is_generic = !generics
652-
.params
653-
.iter()
654-
.all(|param| matches!(param, GenericParam::Lifetime(_)));
655-
let generic_type_paths: Vec<proc_macro2::TokenStream> = generics
656-
.type_params()
657-
.map(|param| {
658-
let ident = &param.ident;
659-
quote! {
660-
<#ident as #bevy_reflect_path::TypePath>
661-
}
662-
})
663-
.collect();
664-
665-
let ident = path_to_type.ident().unwrap().to_string();
666-
let ident = LitStr::new(&ident, path_to_type.span());
667-
668-
let path = {
669-
let path = path_to_type.long_type_path();
670-
671-
if is_generic {
672-
let generics = generic_type_paths.iter().map(|type_path| {
673-
quote! {
674-
#type_path::type_path()
675-
}
676-
});
677-
678-
quote! {
679-
#path + "::<" #(+ #generics)* + ">"
680-
}
681-
} else {
682-
quote! {
683-
#path
684-
}
685-
}
686-
};
687-
688-
let short_path = {
689-
if is_generic {
690-
let generics = generic_type_paths.iter().map(|type_path| {
691-
quote! {
692-
#type_path::short_type_path()
693-
}
694-
});
695-
696-
quote! {
697-
::core::concat!(#ident, "<").to_owned() #(+ #generics)* + ">"
698-
}
699-
} else {
700-
quote! {
701-
#ident.to_owned()
702-
}
703-
}
704-
};
705-
706-
if !path_to_type.is_named() {
707-
quote! {
708-
#bevy_reflect_path::utility::TypePathStorage::new_anonymous(
709-
#path,
710-
#short_path,
711-
)
712-
}
713-
} else {
714-
let crate_name = path_to_type.crate_name();
715-
let module_path = path_to_type.module_path();
716-
717-
quote! {
718-
#bevy_reflect_path::utility::TypePathStorage::new_named(
719-
#path,
720-
#short_path,
721-
#ident.to_owned(),
722-
#crate_name.to_owned(),
723-
#module_path.to_owned(),
724-
)
725-
}
726-
}
727-
}
647+
}

crates/bevy_reflect/bevy_reflect_derive/src/impls/typed.rs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,102 @@
11
use quote::quote;
2+
use syn::{GenericParam, LitStr, spanned::Spanned};
23

3-
use crate::derive_data::{type_path_generator, PathToType, ReflectMeta};
4+
use crate::derive_data::{PathToType, ReflectMeta};
45

6+
/// Returns an expression for a `TypePathStorage`.
7+
pub(crate) fn type_path_generator(meta: &ReflectMeta) -> proc_macro2::TokenStream {
8+
let path_to_type = meta.path_to_type();
9+
let generics = meta.generics();
10+
let bevy_reflect_path = meta.bevy_reflect_path();
11+
// Whether to use `GenericTypedCell` is not dependent on lifetimes
12+
// (which all have to be 'static anyway).
13+
let is_generic = !generics
14+
.params
15+
.iter()
16+
.all(|param| matches!(param, GenericParam::Lifetime(_)));
17+
let generic_type_paths: Vec<proc_macro2::TokenStream> = generics
18+
.type_params()
19+
.map(|param| {
20+
let ident = &param.ident;
21+
quote! {
22+
<#ident as #bevy_reflect_path::TypePath>
23+
}
24+
})
25+
.collect();
26+
27+
let ident = path_to_type.ident().unwrap().to_string();
28+
let ident = LitStr::new(&ident, path_to_type.span());
29+
30+
let path = {
31+
let path = path_to_type.long_type_path();
32+
33+
if is_generic {
34+
let generics = generic_type_paths.iter().map(|type_path| {
35+
quote! {
36+
#type_path::type_path()
37+
}
38+
});
39+
40+
quote! {
41+
#path + "::<" #(+ #generics)* + ">"
42+
}
43+
} else {
44+
quote! {
45+
#path
46+
}
47+
}
48+
};
49+
50+
let short_path = {
51+
if is_generic {
52+
let generics = generic_type_paths.iter().map(|type_path| {
53+
quote! {
54+
#type_path::short_type_path()
55+
}
56+
});
57+
58+
quote! {
59+
::core::concat!(#ident, "<").to_owned() #(+ #generics)* + ">"
60+
}
61+
} else {
62+
quote! {
63+
#ident.to_owned()
64+
}
65+
}
66+
};
67+
68+
if let PathToType::Primitive(name) = path_to_type {
69+
quote! {
70+
#bevy_reflect_path::utility::TypePathStorage::new_primitive(
71+
#path,
72+
#short_path,
73+
#name,
74+
)
75+
}
76+
} else if !path_to_type.is_named() {
77+
quote! {
78+
#bevy_reflect_path::utility::TypePathStorage::new_anonymous(
79+
#path,
80+
#short_path,
81+
)
82+
}
83+
} else {
84+
let crate_name = path_to_type.crate_name();
85+
let module_path = path_to_type.module_path();
86+
87+
quote! {
88+
#bevy_reflect_path::utility::TypePathStorage::new_named(
89+
#path,
90+
#short_path,
91+
#ident.to_owned(),
92+
#crate_name.to_owned(),
93+
#module_path.to_owned(),
94+
)
95+
}
96+
}
97+
}
98+
99+
/// Returns an expression for a `NonGenericTypedCell` or `GenericTypedCell`.
5100
fn static_typed_cell(
6101
meta: &ReflectMeta,
7102
property: TypedProperty,
@@ -54,7 +149,7 @@ pub(crate) fn impl_type_path(meta: &ReflectMeta) -> proc_macro2::TokenStream {
54149
Some(quote! {
55150
const _: () = {
56151
mod private_scope {
57-
// compiles if it can be named with its ident when there are no imports.
152+
// Compiles if it can be named with its ident when there are no imports.
58153
type AssertIsPrimitive = #path_to_type;
59154
}
60155
};

crates/bevy_reflect/bevy_reflect_derive/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
175175

176176
match derive_data {
177177
ReflectDerive::Struct(struct_data) => {
178-
if !struct_data.meta().path_to_type().is_alias() {
178+
if !struct_data.meta().path_to_type().is_aliased() {
179179
return syn::Error::new(
180180
struct_data.meta().path_to_type().span(),
181181
format!("a #[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"] attribute must be specified when using `impl_reflect_struct`")

crates/bevy_reflect/src/type_path.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,66 @@
1+
/// A static accessor to type paths and names.
2+
///
3+
/// The engine uses this trait over [`std::any::type_name`] for stability and flexibility.
4+
///
5+
/// This trait is automatically implemented by the `#[derive(Reflect)]` macro
6+
/// and allows type path information to be processed without an instance of that type.
7+
///
8+
/// Implementors may have difficulty in generating references with static
9+
/// lifetimes. Luckily, this crate comes with some [utility] structs, to make generating these
10+
/// statics much simpler.
11+
///
12+
/// # Stability
13+
///
14+
/// Certain parts of the engine, e.g. [(de)serialization], rely on type paths as identifiers
15+
/// for matching dynamic values to concrete types.
16+
///
17+
/// Using [`std::any::type_name`], a scene containing `my_crate::foo::MyComponent` would break,
18+
/// failing to deserialize if the component was moved to be `my_crate::bar::MyComponent`.
19+
/// This trait, through attributes when deriving itself or [`Reflect`], can ensure breaking changes are avoidable.
20+
///
21+
/// The only external factor we rely on for stability when deriving is the [`module_path!`] macro,
22+
/// only if the derive does not provide a `#[type_path = "..."]` attribute.
23+
///
24+
/// # Example
25+
///
26+
/// ```rust
27+
/// use bevy_reflect::TypePath;
28+
///
29+
/// // This type path will not change with compiler versions or recompiles,
30+
/// // although it will not be the same if the definition is moved.
31+
/// #[derive(TypePath)]
32+
/// struct NonStableTypePath;
33+
///
34+
/// // This type path will never change, even if the definition is moved.
35+
/// #[derive(TypePath)]
36+
/// #[type_path = "my_crate::foo"]
37+
/// struct StableTypePath;
38+
///
39+
/// // Type paths can have any number of path segments.
40+
/// #[derive(TypePath)]
41+
/// #[type_path = "my_crate::foo::bar::baz"]
42+
/// struct DeeplyNestedStableTypePath;
43+
///
44+
/// // Including just a crate name!
45+
/// #[derive(TypePath)]
46+
/// #[type_path = "my_crate"]
47+
/// struct ShallowStableTypePath;
48+
///
49+
/// // We can also rename the identifier/name of types.
50+
/// #[derive(TypePath)]
51+
/// #[type_path = "my_crate::foo"]
52+
/// #[type_name = "RenamedStableTypePath"]
53+
/// struct NamedStableTypePath;
54+
///
55+
/// // Generics are also supported.
56+
/// #[derive(TypePath)]
57+
/// #[type_path = "my_crate::foo"]
58+
/// struct StableGenericTypePath<T: TypePath>(T);
59+
/// ```
60+
///
61+
/// [utility]: crate::utility
62+
/// [(de)serialization]: crate::serde::UntypedReflectDeserializer
63+
/// [`Reflect`]: crate::Reflect
164
pub trait TypePath: 'static {
265
/// Returns the fully qualified path of the underlying type.
366
///

0 commit comments

Comments
 (0)