reflect: stable type path v2 (#7184)

# Objective

- Introduce a stable alternative to
[`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html).
- Rewrite of #5805 with heavy inspiration in design.
- On the path to #5830.
- Part of solving #3327.


## Solution

- Add a `TypePath` trait for static stable type path/name information.
- Add a `TypePath` derive macro.
- Add a `impl_type_path` macro for implementing internal and foreign
types in `bevy_reflect`.

---

## Changelog

- Added `TypePath` trait.
- Added `DynamicTypePath` trait and `get_type_path` method to `Reflect`.
- Added a `TypePath` derive macro.
- Added a `bevy_reflect::impl_type_path` for implementing `TypePath` on
internal and foreign types in `bevy_reflect`.
- Changed `bevy_reflect::utility::(Non)GenericTypeInfoCell` to
`(Non)GenericTypedCell<T>` which allows us to be generic over both
`TypeInfo` and `TypePath`.
- `TypePath` is now a supertrait of `Asset`, `Material` and
`Material2d`.
- `impl_reflect_struct` needs a `#[type_path = "..."]` attribute to be
specified.
- `impl_reflect_value` needs to either specify path starting with a
double colon (`::core::option::Option`) or an `in my_crate::foo`
declaration.
- Added `bevy_reflect_derive::ReflectTypePath`.
- Most uses of `Ident` in `bevy_reflect_derive` changed to use
`ReflectTypePath`.

## Migration Guide

- Implementors of `Asset`, `Material` and `Material2d` now also need to
derive `TypePath`.
- Manual implementors of `Reflect` will need to implement the new
`get_type_path` method.

## Open Questions
- [x] ~This PR currently does not migrate any usages of
`std::any::type_name` to use `bevy_reflect::TypePath` to ease the review
process. Should it?~ Migration will be left to a follow-up PR.
- [ ] This PR adds a lot of `#[derive(TypePath)]` and `T: TypePath` to
satisfy new bounds, mostly when deriving `TypeUuid`. Should we make
`TypePath` a supertrait of `TypeUuid`? [Should we remove `TypeUuid` in
favour of
`TypePath`?](2afbd85532 (r961067892))
This commit is contained in:
radiish 2023-06-05 21:31:20 +01:00 committed by GitHub
parent 94dce091a9
commit 1efc762924
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 2064 additions and 413 deletions

View File

@ -98,7 +98,7 @@ pub struct AssetServerInternal {
/// use bevy_asset::{AssetServer, Handle}; /// use bevy_asset::{AssetServer, Handle};
/// use bevy_ecs::prelude::{Commands, Res}; /// use bevy_ecs::prelude::{Commands, Res};
/// ///
/// # #[derive(Debug, bevy_reflect::TypeUuid)] /// # #[derive(Debug, bevy_reflect::TypeUuid, bevy_reflect::TypePath)]
/// # #[uuid = "00000000-0000-0000-0000-000000000000"] /// # #[uuid = "00000000-0000-0000-0000-000000000000"]
/// # struct Image; /// # struct Image;
/// ///
@ -647,10 +647,10 @@ mod test {
use crate::{loader::LoadedAsset, update_asset_storage_system}; use crate::{loader::LoadedAsset, update_asset_storage_system};
use bevy_app::{App, Update}; use bevy_app::{App, Update};
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_utils::BoxedFuture; use bevy_utils::BoxedFuture;
#[derive(Debug, TypeUuid)] #[derive(Debug, TypeUuid, TypePath)]
#[uuid = "a5189b72-0572-4290-a2e0-96f73a491c44"] #[uuid = "a5189b72-0572-4290-a2e0-96f73a491c44"]
struct PngAsset; struct PngAsset;

View File

@ -488,7 +488,7 @@ mod tests {
#[test] #[test]
fn asset_overwriting() { fn asset_overwriting() {
#[derive(bevy_reflect::TypeUuid)] #[derive(bevy_reflect::TypeUuid, bevy_reflect::TypePath)]
#[uuid = "44115972-f31b-46e5-be5c-2b9aece6a52f"] #[uuid = "44115972-f31b-46e5-be5c-2b9aece6a52f"]
struct MyAsset; struct MyAsset;
let mut app = App::new(); let mut app = App::new();

View File

@ -5,6 +5,7 @@ use crate::{
use anyhow::Error; use anyhow::Error;
use anyhow::Result; use anyhow::Result;
use bevy_ecs::system::{Res, ResMut}; use bevy_ecs::system::{Res, ResMut};
use bevy_reflect::TypePath;
use bevy_reflect::{TypeUuid, TypeUuidDynamic}; use bevy_reflect::{TypeUuid, TypeUuidDynamic};
use bevy_utils::{BoxedFuture, HashMap}; use bevy_utils::{BoxedFuture, HashMap};
use crossbeam_channel::{Receiver, Sender}; use crossbeam_channel::{Receiver, Sender};
@ -47,13 +48,13 @@ pub trait AssetLoader: Send + Sync + 'static {
/// ///
/// In order to load assets into your game you must either add them manually to an asset storage /// In order to load assets into your game you must either add them manually to an asset storage
/// with [`Assets::add`] or load them from the filesystem with [`AssetServer::load`]. /// with [`Assets::add`] or load them from the filesystem with [`AssetServer::load`].
pub trait Asset: TypeUuid + AssetDynamic {} pub trait Asset: TypeUuid + TypePath + AssetDynamic {}
/// An untyped version of the [`Asset`] trait. /// An untyped version of the [`Asset`] trait.
pub trait AssetDynamic: Downcast + TypeUuidDynamic + Send + Sync + 'static {} pub trait AssetDynamic: Downcast + TypeUuidDynamic + Send + Sync + 'static {}
impl_downcast!(AssetDynamic); impl_downcast!(AssetDynamic);
impl<T> Asset for T where T: TypeUuid + AssetDynamic + TypeUuidDynamic {} impl<T> Asset for T where T: TypeUuid + TypePath + AssetDynamic + TypeUuidDynamic {}
impl<T> AssetDynamic for T where T: Send + Sync + 'static + TypeUuidDynamic {} impl<T> AssetDynamic for T where T: Send + Sync + 'static + TypeUuidDynamic {}

View File

@ -1,11 +1,11 @@
use anyhow::Result; use anyhow::Result;
use bevy_asset::{Asset, AssetLoader, LoadContext, LoadedAsset}; use bevy_asset::{Asset, AssetLoader, LoadContext, LoadedAsset};
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_utils::BoxedFuture; use bevy_utils::BoxedFuture;
use std::{io::Cursor, sync::Arc}; use std::{io::Cursor, sync::Arc};
/// A source of audio data /// A source of audio data
#[derive(Debug, Clone, TypeUuid)] #[derive(Debug, Clone, TypeUuid, TypePath)]
#[uuid = "7a14806a-672b-443b-8d16-4f18afefa463"] #[uuid = "7a14806a-672b-443b-8d16-4f18afefa463"]
pub struct AudioSource { pub struct AudioSource {
/// Raw data of the audio source. /// Raw data of the audio source.

View File

@ -1,5 +1,5 @@
use bevy_math::Vec3; use bevy_math::Vec3;
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_transform::prelude::Transform; use bevy_transform::prelude::Transform;
use rodio::{Sink, SpatialSink}; use rodio::{Sink, SpatialSink};
@ -87,7 +87,7 @@ pub trait AudioSinkPlayback {
/// } /// }
/// ``` /// ```
/// ///
#[derive(TypeUuid)] #[derive(TypePath, TypeUuid)]
#[uuid = "8BEE570C-57C2-4FC0-8CFB-983A22F7D981"] #[uuid = "8BEE570C-57C2-4FC0-8CFB-983A22F7D981"]
pub struct AudioSink { pub struct AudioSink {
// This field is an Option in order to allow us to have a safe drop that will detach the sink. // This field is an Option in order to allow us to have a safe drop that will detach the sink.
@ -158,7 +158,7 @@ impl AudioSinkPlayback for AudioSink {
/// } /// }
/// ``` /// ```
/// ///
#[derive(TypeUuid)] #[derive(TypePath, TypeUuid)]
#[uuid = "F3CA4C47-595E-453B-96A7-31C3DDF2A177"] #[uuid = "F3CA4C47-595E-453B-96A7-31C3DDF2A177"]
pub struct SpatialAudioSink { pub struct SpatialAudioSink {
// This field is an Option in order to allow us to have a safe drop that will detach the sink. // This field is an Option in order to allow us to have a safe drop that will detach the sink.

View File

@ -407,7 +407,7 @@ impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
} }
} }
impl_reflect_value!(Entity(Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!((in bevy_ecs) Entity(Hash, PartialEq, Serialize, Deserialize));
impl_from_reflect_value!(Entity); impl_from_reflect_value!(Entity);
#[derive(Clone)] #[derive(Clone)]

View File

@ -12,7 +12,7 @@ use bevy_app::prelude::*;
use bevy_asset::{AddAsset, Handle}; use bevy_asset::{AddAsset, Handle};
use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
use bevy_pbr::StandardMaterial; use bevy_pbr::StandardMaterial;
use bevy_reflect::{Reflect, TypeUuid}; use bevy_reflect::{Reflect, TypePath, TypeUuid};
use bevy_render::{ use bevy_render::{
mesh::{Mesh, MeshVertexAttribute}, mesh::{Mesh, MeshVertexAttribute},
renderer::RenderDevice, renderer::RenderDevice,
@ -58,7 +58,7 @@ impl Plugin for GltfPlugin {
} }
/// Representation of a loaded glTF file. /// Representation of a loaded glTF file.
#[derive(Debug, TypeUuid)] #[derive(Debug, TypeUuid, TypePath)]
#[uuid = "5c7d5f8a-f7b0-4e45-a09e-406c0372fea2"] #[uuid = "5c7d5f8a-f7b0-4e45-a09e-406c0372fea2"]
pub struct Gltf { pub struct Gltf {
pub scenes: Vec<Handle<Scene>>, pub scenes: Vec<Handle<Scene>>,
@ -78,7 +78,7 @@ pub struct Gltf {
/// A glTF node with all of its child nodes, its [`GltfMesh`], /// A glTF node with all of its child nodes, its [`GltfMesh`],
/// [`Transform`](bevy_transform::prelude::Transform) and an optional [`GltfExtras`]. /// [`Transform`](bevy_transform::prelude::Transform) and an optional [`GltfExtras`].
#[derive(Debug, Clone, TypeUuid)] #[derive(Debug, Clone, TypeUuid, TypePath)]
#[uuid = "dad74750-1fd6-460f-ac51-0a7937563865"] #[uuid = "dad74750-1fd6-460f-ac51-0a7937563865"]
pub struct GltfNode { pub struct GltfNode {
pub children: Vec<GltfNode>, pub children: Vec<GltfNode>,
@ -89,7 +89,7 @@ pub struct GltfNode {
/// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive) /// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive)
/// and an optional [`GltfExtras`]. /// and an optional [`GltfExtras`].
#[derive(Debug, Clone, TypeUuid)] #[derive(Debug, Clone, TypeUuid, TypePath)]
#[uuid = "8ceaec9a-926a-4f29-8ee3-578a69f42315"] #[uuid = "8ceaec9a-926a-4f29-8ee3-578a69f42315"]
pub struct GltfMesh { pub struct GltfMesh {
pub primitives: Vec<GltfPrimitive>, pub primitives: Vec<GltfPrimitive>,
@ -97,7 +97,7 @@ pub struct GltfMesh {
} }
/// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`]. /// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`].
#[derive(Debug, Clone, TypeUuid)] #[derive(Debug, Clone, TypeUuid, TypePath)]
#[uuid = "cbfca302-82fd-41cb-af77-cab6b3d50af1"] #[uuid = "cbfca302-82fd-41cb-af77-cab6b3d50af1"]
pub struct GltfPrimitive { pub struct GltfPrimitive {
pub mesh: Handle<Mesh>, pub mesh: Handle<Mesh>,

View File

@ -174,10 +174,12 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use bevy_reflect::TypePath;
use crate::Input; use crate::Input;
/// Used for testing the functionality of [`Input`]. /// Used for testing the functionality of [`Input`].
#[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(TypePath, Copy, Clone, Eq, PartialEq, Hash)]
enum DummyInput { enum DummyInput {
Input1, Input1,
Input2, Input2,

View File

@ -19,7 +19,7 @@ use bevy_ecs::{
SystemParamItem, SystemParamItem,
}, },
}; };
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_render::{ use bevy_render::{
extract_component::ExtractComponentPlugin, extract_component::ExtractComponentPlugin,
mesh::{Mesh, MeshVertexBufferLayout}, mesh::{Mesh, MeshVertexBufferLayout},
@ -59,11 +59,11 @@ use std::marker::PhantomData;
/// ``` /// ```
/// # use bevy_pbr::{Material, MaterialMeshBundle}; /// # use bevy_pbr::{Material, MaterialMeshBundle};
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// # use bevy_reflect::TypeUuid; /// # use bevy_reflect::{TypeUuid, TypePath};
/// # use bevy_render::{render_resource::{AsBindGroup, ShaderRef}, texture::Image, color::Color}; /// # use bevy_render::{render_resource::{AsBindGroup, ShaderRef}, texture::Image, color::Color};
/// # use bevy_asset::{Handle, AssetServer, Assets}; /// # use bevy_asset::{Handle, AssetServer, Assets};
/// ///
/// #[derive(AsBindGroup, TypeUuid, Debug, Clone)] /// #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
/// #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] /// #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
/// pub struct CustomMaterial { /// pub struct CustomMaterial {
/// // Uniform bindings must implement `ShaderType`, which will be used to convert the value to /// // Uniform bindings must implement `ShaderType`, which will be used to convert the value to
@ -106,7 +106,7 @@ use std::marker::PhantomData;
/// @group(1) @binding(2) /// @group(1) @binding(2)
/// var color_sampler: sampler; /// var color_sampler: sampler;
/// ``` /// ```
pub trait Material: AsBindGroup + Send + Sync + Clone + TypeUuid + Sized + 'static { pub trait Material: AsBindGroup + Send + Sync + Clone + TypeUuid + TypePath + Sized {
/// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader /// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader
/// will be used. /// will be used.
fn vertex_shader() -> ShaderRef { fn vertex_shader() -> ShaderRef {

View File

@ -1,15 +1,22 @@
use crate::container_attributes::ReflectTraits; use crate::container_attributes::ReflectTraits;
use crate::field_attributes::{parse_field_attrs, ReflectFieldAttr}; use crate::field_attributes::{parse_field_attrs, ReflectFieldAttr};
use crate::fq_std::{FQAny, FQDefault, FQSend, FQSync}; use crate::fq_std::{FQAny, FQDefault, FQSend, FQSync};
use crate::utility::{members_to_serialization_denylist, WhereClauseOptions}; use crate::type_path::parse_path_no_leading_colon;
use crate::utility::{members_to_serialization_denylist, StringExpr, WhereClauseOptions};
use bit_set::BitSet; use bit_set::BitSet;
use quote::quote; use quote::{quote, ToTokens};
use syn::token::Comma; use syn::token::Comma;
use crate::{utility, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME}; use crate::{
utility, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME,
TYPE_PATH_ATTRIBUTE_NAME,
};
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Data, DeriveInput, Field, Fields, Generics, Ident, Meta, Path, Variant}; use syn::{
parse_str, Data, DeriveInput, Field, Fields, GenericParam, Generics, Ident, LitStr, Meta, Path,
PathSegment, Type, TypeParam, Variant,
};
pub(crate) enum ReflectDerive<'a> { pub(crate) enum ReflectDerive<'a> {
Struct(ReflectStruct<'a>), Struct(ReflectStruct<'a>),
@ -36,9 +43,7 @@ pub(crate) struct ReflectMeta<'a> {
/// The registered traits for this type. /// The registered traits for this type.
traits: ReflectTraits, traits: ReflectTraits,
/// The name of this type. /// The name of this type.
type_name: &'a Ident, type_path: ReflectTypePath<'a>,
/// The generics defined on this type.
generics: &'a Generics,
/// A cached instance of the path to the `bevy_reflect` crate. /// A cached instance of the path to the `bevy_reflect` crate.
bevy_reflect_path: Path, bevy_reflect_path: Path,
/// The documentation for this type, if any /// The documentation for this type, if any
@ -131,8 +136,12 @@ enum ReflectMode {
impl<'a> ReflectDerive<'a> { impl<'a> ReflectDerive<'a> {
pub fn from_input(input: &'a DeriveInput) -> Result<Self, syn::Error> { pub fn from_input(input: &'a DeriveInput) -> Result<Self, syn::Error> {
let mut traits = ReflectTraits::default(); let mut traits = ReflectTraits::default();
// Should indicate whether `#[reflect_value]` was used // Should indicate whether `#[reflect_value]` was used.
let mut reflect_mode = None; let mut reflect_mode = None;
// Should indicate whether `#[type_path = "..."]` was used.
let mut custom_path: Option<Path> = None;
// Should indicate whether `#[type_name = "..."]` was used.
let mut custom_type_name: Option<Ident> = None;
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
let mut doc = crate::documentation::Documentation::default(); let mut doc = crate::documentation::Documentation::default();
@ -177,6 +186,35 @@ impl<'a> ReflectDerive<'a> {
reflect_mode = Some(ReflectMode::Value); reflect_mode = Some(ReflectMode::Value);
} }
Meta::NameValue(pair) if pair.path.is_ident(TYPE_PATH_ATTRIBUTE_NAME) => {
let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = &pair.value else {
return Err(syn::Error::new(
pair.span(),
format_args!("`#[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"]` must be a string literal"),
));
};
custom_path = Some(syn::parse::Parser::parse_str(
parse_path_no_leading_colon,
&lit.value(),
)?);
}
Meta::NameValue(pair) if pair.path.is_ident(TYPE_NAME_ATTRIBUTE_NAME) => {
let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = &pair.value else {
return Err(syn::Error::new(
pair.span(),
format_args!("`#[{TYPE_NAME_ATTRIBUTE_NAME} = \"...\"]` must be a string literal"),
));
};
custom_type_name = Some(parse_str(&lit.value())?);
}
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
Meta::NameValue(pair) if pair.path.is_ident("doc") => { Meta::NameValue(pair) if pair.path.is_ident("doc") => {
if let syn::Expr::Lit(syn::ExprLit { if let syn::Expr::Lit(syn::ExprLit {
@ -190,8 +228,27 @@ impl<'a> ReflectDerive<'a> {
_ => continue, _ => continue,
} }
} }
match (&mut custom_path, custom_type_name) {
(Some(path), custom_type_name) => {
let ident = custom_type_name.unwrap_or_else(|| input.ident.clone());
path.segments.push(PathSegment::from(ident));
}
(None, Some(name)) => {
return Err(syn::Error::new(
name.span(),
format!("cannot use `#[{TYPE_NAME_ATTRIBUTE_NAME} = \"...\"]` without a `#[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"]` attribute."),
));
}
_ => (),
}
let meta = ReflectMeta::new(&input.ident, &input.generics, traits); let type_path = ReflectTypePath::Internal {
ident: &input.ident,
custom_path,
generics: &input.generics,
};
let meta = ReflectMeta::new(type_path, traits);
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
let meta = meta.with_docs(doc); let meta = meta.with_docs(doc);
@ -233,6 +290,16 @@ impl<'a> ReflectDerive<'a> {
}; };
} }
pub fn meta(&self) -> &ReflectMeta<'a> {
match self {
ReflectDerive::Struct(data)
| ReflectDerive::TupleStruct(data)
| ReflectDerive::UnitStruct(data) => data.meta(),
ReflectDerive::Enum(data) => data.meta(),
ReflectDerive::Value(meta) => meta,
}
}
fn collect_struct_fields(fields: &'a Fields) -> Result<Vec<StructField<'a>>, syn::Error> { fn collect_struct_fields(fields: &'a Fields) -> Result<Vec<StructField<'a>>, syn::Error> {
let sifter: utility::ResultSifter<StructField<'a>> = fields let sifter: utility::ResultSifter<StructField<'a>> = fields
.iter() .iter()
@ -288,11 +355,10 @@ impl<'a> ReflectDerive<'a> {
} }
impl<'a> ReflectMeta<'a> { impl<'a> ReflectMeta<'a> {
pub fn new(type_name: &'a Ident, generics: &'a Generics, traits: ReflectTraits) -> Self { pub fn new(type_path: ReflectTypePath<'a>, traits: ReflectTraits) -> Self {
Self { Self {
traits, traits,
type_name, type_path,
generics,
bevy_reflect_path: utility::get_bevy_reflect_path(), bevy_reflect_path: utility::get_bevy_reflect_path(),
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
docs: Default::default(), docs: Default::default(),
@ -311,13 +377,8 @@ impl<'a> ReflectMeta<'a> {
} }
/// The name of this struct. /// The name of this struct.
pub fn type_name(&self) -> &'a Ident { pub fn type_path(&self) -> &ReflectTypePath<'a> {
self.type_name &self.type_path
}
/// The generics associated with this struct.
pub fn generics(&self) -> &'a Generics {
self.generics
} }
/// The cached `bevy_reflect` path. /// The cached `bevy_reflect` path.
@ -330,14 +391,7 @@ impl<'a> ReflectMeta<'a> {
&self, &self,
where_clause_options: &WhereClauseOptions, where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
crate::registration::impl_get_type_registration( crate::registration::impl_get_type_registration(self, where_clause_options, None)
self.type_name,
&self.bevy_reflect_path,
self.traits.idents(),
self.generics,
where_clause_options,
None,
)
} }
/// The collection of docstrings for this type, if any. /// The collection of docstrings for this type, if any.
@ -368,13 +422,8 @@ impl<'a> ReflectStruct<'a> {
&self, &self,
where_clause_options: &WhereClauseOptions, where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let reflect_path = self.meta.bevy_reflect_path();
crate::registration::impl_get_type_registration( crate::registration::impl_get_type_registration(
self.meta.type_name(), self.meta(),
reflect_path,
self.meta.traits().idents(),
self.meta.generics(),
where_clause_options, where_clause_options,
Some(&self.serialization_denylist), Some(&self.serialization_denylist),
) )
@ -421,6 +470,7 @@ impl<'a> ReflectStruct<'a> {
active_trait_bounds: quote! { #bevy_reflect_path::Reflect }, active_trait_bounds: quote! { #bevy_reflect_path::Reflect },
ignored_types: self.ignored_types().into(), ignored_types: self.ignored_types().into(),
ignored_trait_bounds: quote! { #FQAny + #FQSend + #FQSync }, ignored_trait_bounds: quote! { #FQAny + #FQSend + #FQSync },
..WhereClauseOptions::type_path_bounds(self.meta())
} }
} }
} }
@ -433,7 +483,7 @@ impl<'a> ReflectEnum<'a> {
/// Returns the given ident as a qualified unit variant of this enum. /// Returns the given ident as a qualified unit variant of this enum.
pub fn get_unit(&self, variant: &Ident) -> proc_macro2::TokenStream { pub fn get_unit(&self, variant: &Ident) -> proc_macro2::TokenStream {
let name = self.meta.type_name; let name = self.meta.type_path();
quote! { quote! {
#name::#variant #name::#variant
} }
@ -479,6 +529,7 @@ impl<'a> ReflectEnum<'a> {
active_trait_bounds: quote! { #bevy_reflect_path::FromReflect }, active_trait_bounds: quote! { #bevy_reflect_path::FromReflect },
ignored_types: self.ignored_types().into(), ignored_types: self.ignored_types().into(),
ignored_trait_bounds: quote! { #FQAny + #FQSend + #FQSync + #FQDefault }, ignored_trait_bounds: quote! { #FQAny + #FQSend + #FQSync + #FQDefault },
..WhereClauseOptions::type_path_bounds(self.meta())
} }
} }
} }
@ -509,3 +560,355 @@ impl<'a> EnumVariant<'a> {
} }
} }
} }
/// Represents a path to a type.
///
/// This is used over [`struct@Ident`] or [`Path`]
/// to have the correct semantics for [deriving `TypePath`].
///
/// The type can always be reached with its [`ToTokens`] implementation.
///
/// The [`short_type_path`], [`type_ident`], [`crate_name`], and [`module_path`] methods
/// have corresponding methods on the `TypePath` trait.
/// [`long_type_path`] corresponds to the `type_path` method on `TypePath`.
///
/// [deriving `TypePath`]: crate::derive_type_path
/// [`long_type_path`]: ReflectTypePath::long_type_path
/// [`short_type_path`]: ReflectTypePath::short_type_path
/// [`type_ident`]: ReflectTypePath::type_ident
/// [`crate_name`]: ReflectTypePath::crate_name
/// [`module_path`]: ReflectTypePath::module_path
///
/// # Example
///
/// ```rust,ignore
/// # use syn::parse_quote;
/// # use bevy_reflect_derive::ReflectTypePath;
/// let path: syn::Path = parse_quote!(::core::marker::PhantomData)?;
///
/// let type_path = ReflectTypePath::External {
/// path,
/// custom_path: None,
/// };
///
/// // Eqivalent to "core::marker".
/// let module_path = type_path.module_path();
/// # Ok::<(), syn::Error>(())
/// ```
///
pub(crate) enum ReflectTypePath<'a> {
/// Types without a crate/module that can be named from any scope (e.g. `bool`).
Primitive(&'a Ident),
/// Using `::my_crate::foo::Bar` syntax.
///
/// May have a seperate custom path used for the `TypePath` implementation.
External {
path: &'a Path,
custom_path: Option<Path>,
generics: &'a Generics,
},
/// The name of a type relative to its scope.
///
/// The type must be able to be reached with just its name.
///
/// May have a seperate alias path used for the `TypePath` implementation.
///
/// Module and crate are found with [`module_path!()`](core::module_path),
/// if there is no custom path specified.
Internal {
ident: &'a Ident,
custom_path: Option<Path>,
generics: &'a Generics,
},
/// Any [`syn::Type`] with only a defined `type_path` and `short_type_path`.
#[allow(dead_code)]
// Not currently used but may be useful in the future due to its generality.
Anonymous {
qualified_type: Type,
long_type_path: StringExpr,
short_type_path: StringExpr,
},
}
impl<'a> ReflectTypePath<'a> {
/// Returns the path interpreted as an [`struct@Ident`].
///
/// Returns [`None`] if [anonymous].
///
/// [anonymous]: ReflectTypePath::Anonymous
pub fn get_ident(&self) -> Option<&Ident> {
match self {
Self::Internal {
ident, custom_path, ..
} => Some(
custom_path
.as_ref()
.map(|path| &path.segments.last().unwrap().ident)
.unwrap_or(ident),
),
Self::External {
path, custom_path, ..
} => Some(
&custom_path
.as_ref()
.unwrap_or(path)
.segments
.last()
.unwrap()
.ident,
),
Self::Primitive(ident) => Some(ident),
_ => None,
}
}
/// The generics associated with the type.
///
/// Empty if [anonymous] or [primitive].
///
/// [primitive]: ReflectTypePath::Primitive
/// [anonymous]: ReflectTypePath::Anonymous
pub fn generics(&self) -> &'a Generics {
// Use a constant because we need to return a reference of at least 'a.
const EMPTY_GENERICS: &Generics = &Generics {
gt_token: None,
lt_token: None,
where_clause: None,
params: Punctuated::new(),
};
match self {
Self::Internal { generics, .. } | Self::External { generics, .. } => generics,
_ => EMPTY_GENERICS,
}
}
/// Whether an implementation of `Typed` or `TypePath` should be generic.
///
/// Returning true that it should use a `GenericTypeCell` in its implementation.
pub fn impl_is_generic(&self) -> bool {
// Whether to use `GenericTypeCell` is not dependent on lifetimes
// (which all have to be 'static anyway).
!self
.generics()
.params
.iter()
.all(|param| matches!(param, GenericParam::Lifetime(_)))
}
/// Returns the path interpreted as a [`Path`].
///
/// Returns [`None`] if [anonymous], [primitive],
/// or a [`ReflectTypePath::Internal`] without a custom path.
///
/// [primitive]: ReflectTypePath::Primitive
/// [anonymous]: ReflectTypePath::Anonymous
pub fn get_path(&self) -> Option<&Path> {
match self {
Self::Internal { custom_path, .. } => custom_path.as_ref(),
Self::External {
path, custom_path, ..
} => Some(custom_path.as_ref().unwrap_or(path)),
_ => None,
}
}
/// Returns whether this [internal] or [external] path has a custom path.
///
/// [internal]: ReflectTypePath::Internal
/// [external]: ReflectTypePath::External
pub fn has_custom_path(&self) -> bool {
match self {
Self::Internal { custom_path, .. } | Self::External { custom_path, .. } => {
custom_path.is_some()
}
_ => false,
}
}
/// Returns a [`StringExpr`] representing the name of the type's crate.
///
/// Returns [`None`] if the type is [primitive] or [anonymous].
///
/// For non-customised [internal] paths this is created from [`module_path`].
///
/// For `Option<PhantomData>`, this is `"core"`.
///
/// [primitive]: ReflectTypePath::Primitive
/// [anonymous]: ReflectTypePath::Anonymous
/// [internal]: ReflectTypePath::Internal
pub fn crate_name(&self) -> Option<StringExpr> {
if let Some(path) = self.get_path() {
let crate_name = &path.segments.first().unwrap().ident;
return Some(StringExpr::from(crate_name));
}
match self {
Self::Internal { .. } => Some(StringExpr::Borrowed(quote! {
::core::module_path!()
.split(':')
.next()
.unwrap()
})),
Self::External { .. } => unreachable!(),
_ => None,
}
}
/// Combines type generics and const generics into one [`StringExpr`].
///
/// This string can be used with a `GenericTypePathCell` in a `TypePath` implementation.
///
/// The `ty_generic_fn` param maps [`TypeParam`]s to [`StringExpr`]s.
fn reduce_generics(
generics: &Generics,
mut ty_generic_fn: impl FnMut(&TypeParam) -> StringExpr,
) -> StringExpr {
let mut params = generics.params.iter().filter_map(|param| match param {
GenericParam::Type(type_param) => Some(ty_generic_fn(type_param)),
GenericParam::Const(const_param) => {
let ident = &const_param.ident;
let ty = &const_param.ty;
Some(StringExpr::Owned(quote! {
<#ty as ::std::string::ToString>::to_string(&#ident)
}))
}
GenericParam::Lifetime(_) => None,
});
params
.next()
.into_iter()
.chain(params.flat_map(|x| [StringExpr::from_str(", "), x]))
.collect()
}
/// Returns a [`StringExpr`] representing the "type path" of the type.
///
/// For `Option<PhantomData>`, this is `"core::option::Option<core::marker::PhantomData>"`.
pub fn long_type_path(&self, bevy_reflect_path: &Path) -> StringExpr {
match self {
Self::Primitive(ident) => StringExpr::from(ident),
Self::Anonymous { long_type_path, .. } => long_type_path.clone(),
Self::Internal { generics, .. } | Self::External { generics, .. } => {
let ident = self.type_ident().unwrap();
let module_path = self.module_path().unwrap();
if self.impl_is_generic() {
let generics = ReflectTypePath::reduce_generics(
generics,
|TypeParam { ident, .. }| {
StringExpr::Borrowed(quote! {
<#ident as #bevy_reflect_path::TypePath>::type_path()
})
},
);
StringExpr::from_iter([
module_path,
StringExpr::from_str("::"),
ident,
StringExpr::from_str("<"),
generics,
StringExpr::from_str(">"),
])
} else {
StringExpr::from_iter([module_path, StringExpr::from_str("::"), ident])
}
}
}
}
/// Returns a [`StringExpr`] representing the "short path" of the type.
///
/// For `Option<PhantomData>`, this is `"Option<PhantomData>"`.
pub fn short_type_path(&self, bevy_reflect_path: &Path) -> StringExpr {
match self {
Self::Anonymous {
short_type_path, ..
} => short_type_path.clone(),
Self::Primitive(ident) => StringExpr::from(ident),
Self::External { generics, .. } | Self::Internal { generics, .. } => {
let ident = self.type_ident().unwrap();
if self.impl_is_generic() {
let generics = ReflectTypePath::reduce_generics(
generics,
|TypeParam { ident, .. }| {
StringExpr::Borrowed(quote! {
<#ident as #bevy_reflect_path::TypePath>::short_type_path()
})
},
);
StringExpr::from_iter([
ident,
StringExpr::from_str("<"),
generics,
StringExpr::from_str(">"),
])
} else {
ident
}
}
}
}
/// Returns a [`StringExpr`] representing the path to the module
/// that the type is in.
///
/// Returns [`None`] if the type is [primitive] or [anonymous].
///
/// For non-customised [internal] paths this is created from [`module_path`].
///
/// For `Option<PhantomData>`, this is `"core::option"`.
///
/// [primitive]: ReflectTypePath::Primitive
/// [anonymous]: ReflectTypePath::Anonymous
/// [internal]: ReflectTypePath::Internal
pub fn module_path(&self) -> Option<StringExpr> {
if let Some(path) = self.get_path() {
let path_string = path
.segments
.pairs()
.take(path.segments.len() - 1)
.map(|pair| pair.value().ident.to_string())
.reduce(|path, ident| path + "::" + &ident)
.unwrap();
let path_lit = LitStr::new(&path_string, path.span());
return Some(StringExpr::from_lit(&path_lit));
}
match self {
Self::Internal { .. } => Some(StringExpr::Const(quote! {
::core::module_path!()
})),
Self::External { .. } => unreachable!(),
_ => None,
}
}
/// Returns a [`StringExpr`] representing the type's final ident.
///
/// Returns [`None`] if the type is [anonymous].
///
/// This is not necessarily a valid qualified path to the type.
///
/// For `Option<PhantomData>`, this is `"Option"`.
///
/// [anonymous]: ReflectTypePath::Anonymous
pub fn type_ident(&self) -> Option<StringExpr> {
self.get_ident().map(StringExpr::from)
}
}
impl<'a> ToTokens for ReflectTypePath<'a> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
Self::Internal { ident, .. } | Self::Primitive(ident) => ident.to_tokens(tokens),
Self::External { path, .. } => path.to_tokens(tokens),
Self::Anonymous { qualified_type, .. } => qualified_type.to_tokens(tokens),
}
}
}

View File

@ -22,13 +22,13 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
/// Implements `FromReflect` for the given value type /// Implements `FromReflect` for the given value type
pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream { pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
let type_name = meta.type_name(); let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path(); let bevy_reflect_path = meta.bevy_reflect_path();
let (impl_generics, ty_generics, where_clause) = meta.generics().split_for_impl(); let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
TokenStream::from(quote! { TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #type_name #ty_generics #where_clause { impl #impl_generics #bevy_reflect_path::FromReflect for #type_path #ty_generics #where_clause {
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> { fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
#FQOption::Some(#FQClone::clone(<dyn #FQAny>::downcast_ref::<#type_name #ty_generics>(<dyn #bevy_reflect_path::Reflect>::as_any(reflect))?)) #FQOption::Some(#FQClone::clone(<dyn #FQAny>::downcast_ref::<#type_path #ty_generics>(<dyn #bevy_reflect_path::Reflect>::as_any(reflect))?))
} }
} }
}) })
@ -38,7 +38,7 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream { pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
let fqoption = FQOption.into_token_stream(); let fqoption = FQOption.into_token_stream();
let type_name = reflect_enum.meta().type_name(); let enum_path = reflect_enum.meta().type_path();
let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path(); let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path();
let ref_value = Ident::new("__param0", Span::call_site()); let ref_value = Ident::new("__param0", Span::call_site());
@ -47,8 +47,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
variant_constructors, variant_constructors,
} = get_variant_constructors(reflect_enum, &ref_value, false); } = get_variant_constructors(reflect_enum, &ref_value, false);
let (impl_generics, ty_generics, where_clause) = let (impl_generics, ty_generics, where_clause) = enum_path.generics().split_for_impl();
reflect_enum.meta().generics().split_for_impl();
// Add FromReflect bound for each active field // Add FromReflect bound for each active field
let where_from_reflect_clause = extend_where_clause( let where_from_reflect_clause = extend_where_clause(
@ -58,11 +57,12 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
ignored_types: reflect_enum.ignored_types().into_boxed_slice(), ignored_types: reflect_enum.ignored_types().into_boxed_slice(),
active_trait_bounds: quote!(#bevy_reflect_path::FromReflect), active_trait_bounds: quote!(#bevy_reflect_path::FromReflect),
ignored_trait_bounds: quote!(#FQDefault), ignored_trait_bounds: quote!(#FQDefault),
..WhereClauseOptions::type_path_bounds(reflect_enum.meta())
}, },
); );
TokenStream::from(quote! { TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #type_name #ty_generics #where_from_reflect_clause { impl #impl_generics #bevy_reflect_path::FromReflect for #enum_path #ty_generics #where_from_reflect_clause {
fn from_reflect(#ref_value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> { fn from_reflect(#ref_value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) { if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) {
match #bevy_reflect_path::Enum::variant_name(#ref_value) { match #bevy_reflect_path::Enum::variant_name(#ref_value) {
@ -90,8 +90,7 @@ impl MemberValuePair {
fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> TokenStream { fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> TokenStream {
let fqoption = FQOption.into_token_stream(); let fqoption = FQOption.into_token_stream();
let struct_name = reflect_struct.meta().type_name(); let struct_path = reflect_struct.meta().type_path();
let generics = reflect_struct.meta().generics();
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path(); let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
let ref_struct = Ident::new("__ref_struct", Span::call_site()); let ref_struct = Ident::new("__ref_struct", Span::call_site());
@ -129,7 +128,11 @@ fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> Token
) )
}; };
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = reflect_struct
.meta()
.type_path()
.generics()
.split_for_impl();
// Add FromReflect bound for each active field // Add FromReflect bound for each active field
let where_from_reflect_clause = extend_where_clause( let where_from_reflect_clause = extend_where_clause(
@ -143,11 +146,12 @@ fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> Token
} else { } else {
quote!(#FQDefault) quote!(#FQDefault)
}, },
..WhereClauseOptions::type_path_bounds(reflect_struct.meta())
}, },
); );
TokenStream::from(quote! { TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #struct_name #ty_generics #where_from_reflect_clause impl #impl_generics #bevy_reflect_path::FromReflect for #struct_path #ty_generics #where_from_reflect_clause
{ {
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> { fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct) = #bevy_reflect_path::Reflect::reflect_ref(reflect) { if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct) = #bevy_reflect_path::Reflect::reflect_ref(reflect) {

View File

@ -1,7 +1,7 @@
use crate::derive_data::{EnumVariant, EnumVariantFields, ReflectEnum, StructField}; use crate::derive_data::{EnumVariant, EnumVariantFields, ReflectEnum, StructField};
use crate::enum_utility::{get_variant_constructors, EnumVariantConstructors}; use crate::enum_utility::{get_variant_constructors, EnumVariantConstructors};
use crate::fq_std::{FQAny, FQBox, FQOption, FQResult}; use crate::fq_std::{FQAny, FQBox, FQOption, FQResult};
use crate::impls::impl_typed; use crate::impls::{impl_type_path, impl_typed};
use crate::utility::extend_where_clause; use crate::utility::extend_where_clause;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::{Ident, Span}; use proc_macro2::{Ident, Span};
@ -10,7 +10,7 @@ use syn::Fields;
pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream { pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path(); let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path();
let enum_name = reflect_enum.meta().type_name(); let enum_path = reflect_enum.meta().type_path();
let ref_name = Ident::new("__name_param", Span::call_site()); let ref_name = Ident::new("__name_param", Span::call_site());
let ref_index = Ident::new("__index_param", Span::call_site()); let ref_index = Ident::new("__index_param", Span::call_site());
@ -59,7 +59,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
} }
}); });
let string_name = enum_name.to_string(); let string_name = enum_path.get_ident().unwrap().to_string();
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
let info_generator = { let info_generator = {
@ -77,22 +77,23 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
}; };
let typed_impl = impl_typed( let typed_impl = impl_typed(
enum_name, reflect_enum.meta(),
reflect_enum.meta().generics(),
&where_clause_options, &where_clause_options,
quote! { quote! {
let variants = [#(#variant_info),*]; let variants = [#(#variant_info),*];
let info = #info_generator; let info = #info_generator;
#bevy_reflect_path::TypeInfo::Enum(info) #bevy_reflect_path::TypeInfo::Enum(info)
}, },
bevy_reflect_path,
); );
let type_path_impl = impl_type_path(reflect_enum.meta(), &where_clause_options);
let get_type_registration_impl = reflect_enum let get_type_registration_impl = reflect_enum
.meta() .meta()
.get_type_registration(&where_clause_options); .get_type_registration(&where_clause_options);
let (impl_generics, ty_generics, where_clause) = let (impl_generics, ty_generics, where_clause) =
reflect_enum.meta().generics().split_for_impl(); reflect_enum.meta().type_path().generics().split_for_impl();
let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options); let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options);
@ -101,7 +102,9 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
#typed_impl #typed_impl
impl #impl_generics #bevy_reflect_path::Enum for #enum_name #ty_generics #where_reflect_clause { #type_path_impl
impl #impl_generics #bevy_reflect_path::Enum for #enum_path #ty_generics #where_reflect_clause {
fn field(&self, #ref_name: &str) -> #FQOption<&dyn #bevy_reflect_path::Reflect> { fn field(&self, #ref_name: &str) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
match self { match self {
#(#enum_field,)* #(#enum_field,)*
@ -185,7 +188,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
} }
} }
impl #impl_generics #bevy_reflect_path::Reflect for #enum_name #ty_generics #where_reflect_clause { impl #impl_generics #bevy_reflect_path::Reflect for #enum_path #ty_generics #where_reflect_clause {
#[inline] #[inline]
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
::core::any::type_name::<Self>() ::core::any::type_name::<Self>()
@ -196,6 +199,11 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info()) #FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> { fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self self

View File

@ -7,5 +7,6 @@ mod values;
pub(crate) use enums::impl_enum; pub(crate) use enums::impl_enum;
pub(crate) use structs::impl_struct; pub(crate) use structs::impl_struct;
pub(crate) use tuple_structs::impl_tuple_struct; pub(crate) use tuple_structs::impl_tuple_struct;
pub(crate) use typed::impl_type_path;
pub(crate) use typed::impl_typed; pub(crate) use typed::impl_typed;
pub(crate) use values::impl_value; pub(crate) use values::impl_value;

View File

@ -1,5 +1,5 @@
use crate::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult}; use crate::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult};
use crate::impls::impl_typed; use crate::impls::{impl_type_path, impl_typed};
use crate::utility::{extend_where_clause, ident_or_index}; use crate::utility::{extend_where_clause, ident_or_index};
use crate::ReflectStruct; use crate::ReflectStruct;
use proc_macro::TokenStream; use proc_macro::TokenStream;
@ -10,7 +10,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
let fqoption = FQOption.into_token_stream(); let fqoption = FQOption.into_token_stream();
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path(); let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
let struct_name = reflect_struct.meta().type_name(); let struct_path = reflect_struct.meta().type_path();
let field_names = reflect_struct let field_names = reflect_struct
.active_fields() .active_fields()
@ -64,7 +64,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
} }
}; };
let string_name = struct_name.to_string(); let string_name = struct_path.get_ident().unwrap().to_string();
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
let info_generator = { let info_generator = {
@ -83,20 +83,24 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
let where_clause_options = reflect_struct.where_clause_options(); let where_clause_options = reflect_struct.where_clause_options();
let typed_impl = impl_typed( let typed_impl = impl_typed(
struct_name, reflect_struct.meta(),
reflect_struct.meta().generics(),
&where_clause_options, &where_clause_options,
quote! { quote! {
let fields = [#field_generator]; let fields = [#field_generator];
let info = #info_generator; let info = #info_generator;
#bevy_reflect_path::TypeInfo::Struct(info) #bevy_reflect_path::TypeInfo::Struct(info)
}, },
bevy_reflect_path,
); );
let type_path_impl = impl_type_path(reflect_struct.meta(), &where_clause_options);
let get_type_registration_impl = reflect_struct.get_type_registration(&where_clause_options); let get_type_registration_impl = reflect_struct.get_type_registration(&where_clause_options);
let (impl_generics, ty_generics, where_clause) =
reflect_struct.meta().generics().split_for_impl(); let (impl_generics, ty_generics, where_clause) = reflect_struct
.meta()
.type_path()
.generics()
.split_for_impl();
let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options); let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options);
@ -105,7 +109,9 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
#typed_impl #typed_impl
impl #impl_generics #bevy_reflect_path::Struct for #struct_name #ty_generics #where_reflect_clause { #type_path_impl
impl #impl_generics #bevy_reflect_path::Struct for #struct_path #ty_generics #where_reflect_clause {
fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::Reflect> { fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
match name { match name {
#(#field_names => #fqoption::Some(&self.#field_idents),)* #(#field_names => #fqoption::Some(&self.#field_idents),)*
@ -157,7 +163,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
} }
} }
impl #impl_generics #bevy_reflect_path::Reflect for #struct_name #ty_generics #where_reflect_clause { impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
#[inline] #[inline]
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
::core::any::type_name::<Self>() ::core::any::type_name::<Self>()
@ -168,6 +174,11 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info()) #FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> { fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self self

View File

@ -1,5 +1,5 @@
use crate::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult}; use crate::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult};
use crate::impls::impl_typed; use crate::impls::{impl_type_path, impl_typed};
use crate::utility::extend_where_clause; use crate::utility::extend_where_clause;
use crate::ReflectStruct; use crate::ReflectStruct;
use proc_macro::TokenStream; use proc_macro::TokenStream;
@ -11,7 +11,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
let fqoption = FQOption.into_token_stream(); let fqoption = FQOption.into_token_stream();
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path(); let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
let struct_name = reflect_struct.meta().type_name(); let struct_path = reflect_struct.meta().type_path();
let field_idents = reflect_struct let field_idents = reflect_struct
.active_fields() .active_fields()
@ -58,7 +58,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
} }
}; };
let string_name = struct_name.to_string(); let string_name = struct_path.get_ident().unwrap().to_string();
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
let info_generator = { let info_generator = {
@ -76,19 +76,22 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
}; };
let typed_impl = impl_typed( let typed_impl = impl_typed(
struct_name, reflect_struct.meta(),
reflect_struct.meta().generics(),
&where_clause_options, &where_clause_options,
quote! { quote! {
let fields = [#field_generator]; let fields = [#field_generator];
let info = #info_generator; let info = #info_generator;
#bevy_reflect_path::TypeInfo::TupleStruct(info) #bevy_reflect_path::TypeInfo::TupleStruct(info)
}, },
bevy_reflect_path,
); );
let (impl_generics, ty_generics, where_clause) = let type_path_impl = impl_type_path(reflect_struct.meta(), &where_clause_options);
reflect_struct.meta().generics().split_for_impl();
let (impl_generics, ty_generics, where_clause) = reflect_struct
.meta()
.type_path()
.generics()
.split_for_impl();
let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options); let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options);
@ -97,7 +100,9 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
#typed_impl #typed_impl
impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name #ty_generics #where_reflect_clause { #type_path_impl
impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_path #ty_generics #where_reflect_clause {
fn field(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::Reflect> { fn field(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
match index { match index {
#(#field_indices => #fqoption::Some(&self.#field_idents),)* #(#field_indices => #fqoption::Some(&self.#field_idents),)*
@ -128,7 +133,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
} }
} }
impl #impl_generics #bevy_reflect_path::Reflect for #struct_name #ty_generics #where_reflect_clause { impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
#[inline] #[inline]
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
::core::any::type_name::<Self>() ::core::any::type_name::<Self>()
@ -139,6 +144,11 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info()) #FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> { fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self self

View File

@ -1,43 +1,149 @@
use crate::utility::{extend_where_clause, WhereClauseOptions}; use crate::utility::{extend_where_clause, StringExpr, WhereClauseOptions};
use proc_macro2::Ident; use quote::{quote, ToTokens};
use quote::quote;
use syn::{Generics, Path};
#[allow(clippy::too_many_arguments)] use crate::{
pub(crate) fn impl_typed( derive_data::{ReflectMeta, ReflectTypePath},
type_name: &Ident, utility::wrap_in_option,
generics: &Generics, };
where_clause_options: &WhereClauseOptions,
/// Returns an expression for a `NonGenericTypeCell` or `GenericTypeCell` to generate `'static` references.
fn static_type_cell(
meta: &ReflectMeta,
property: TypedProperty,
generator: proc_macro2::TokenStream, generator: proc_macro2::TokenStream,
bevy_reflect_path: &Path,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let is_generic = !generics.params.is_empty(); let bevy_reflect_path = meta.bevy_reflect_path();
if meta.type_path().impl_is_generic() {
let cell_type = match property {
TypedProperty::TypePath => quote!(GenericTypePathCell),
TypedProperty::TypeInfo => quote!(GenericTypeInfoCell),
};
let static_generator = if is_generic {
quote! { quote! {
static CELL: #bevy_reflect_path::utility::GenericTypeInfoCell = #bevy_reflect_path::utility::GenericTypeInfoCell::new(); static CELL: #bevy_reflect_path::utility::#cell_type = #bevy_reflect_path::utility::#cell_type::new();
CELL.get_or_insert::<Self, _>(|| { CELL.get_or_insert::<Self, _>(|| {
#generator #generator
}) })
} }
} else { } else {
let cell_type = match property {
TypedProperty::TypePath => unreachable!(
"Cannot have a non-generic type path cell. Use string literals and core::concat instead."
),
TypedProperty::TypeInfo => quote!(NonGenericTypeInfoCell),
};
quote! { quote! {
static CELL: #bevy_reflect_path::utility::NonGenericTypeInfoCell = #bevy_reflect_path::utility::NonGenericTypeInfoCell::new(); static CELL: #bevy_reflect_path::utility::#cell_type = #bevy_reflect_path::utility::#cell_type::new();
CELL.get_or_set(|| { CELL.get_or_set(|| {
#generator #generator
}) })
} }
}
}
#[derive(Clone, Copy)]
pub(crate) enum TypedProperty {
TypeInfo,
TypePath,
}
pub(crate) fn impl_type_path(
meta: &ReflectMeta,
where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream {
let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path();
let (long_type_path, short_type_path) = if type_path.impl_is_generic() {
let long_path_cell = static_type_cell(
meta,
TypedProperty::TypePath,
type_path.long_type_path(bevy_reflect_path).into_owned(),
);
let short_path_cell = static_type_cell(
meta,
TypedProperty::TypePath,
type_path.short_type_path(bevy_reflect_path).into_owned(),
);
(
long_path_cell.to_token_stream(),
short_path_cell.to_token_stream(),
)
} else {
(
type_path.long_type_path(bevy_reflect_path).into_borrowed(),
type_path.short_type_path(bevy_reflect_path).into_borrowed(),
)
}; };
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let type_ident = wrap_in_option(type_path.type_ident().map(StringExpr::into_borrowed));
let module_path = wrap_in_option(type_path.module_path().map(StringExpr::into_borrowed));
let crate_name = wrap_in_option(type_path.crate_name().map(StringExpr::into_borrowed));
let primitive_assert = if let ReflectTypePath::Primitive(_) = type_path {
Some(quote! {
const _: () = {
mod private_scope {
// Compiles if it can be named when there are no imports.
type AssertIsPrimitive = #type_path;
}
};
})
} else {
None
};
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
// Add Typed bound for each active field // Add Typed bound for each active field
let where_reflect_clause = extend_where_clause(where_clause, where_clause_options); let where_reflect_clause = extend_where_clause(where_clause, where_clause_options);
quote! { quote! {
impl #impl_generics #bevy_reflect_path::Typed for #type_name #ty_generics #where_reflect_clause { #primitive_assert
fn type_info() -> &'static #bevy_reflect_path::TypeInfo {
#static_generator impl #impl_generics #bevy_reflect_path::TypePath for #type_path #ty_generics #where_reflect_clause {
fn type_path() -> &'static str {
#long_type_path
}
fn short_type_path() -> &'static str {
#short_type_path
}
fn type_ident() -> Option<&'static str> {
#type_ident
}
fn crate_name() -> Option<&'static str> {
#crate_name
}
fn module_path() -> Option<&'static str> {
#module_path
}
}
}
}
pub(crate) fn impl_typed(
meta: &ReflectMeta,
where_clause_options: &WhereClauseOptions,
type_info_generator: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path();
let type_info_cell = static_type_cell(meta, TypedProperty::TypeInfo, type_info_generator);
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
let where_reflect_clause = extend_where_clause(where_clause, where_clause_options);
quote! {
impl #impl_generics #bevy_reflect_path::Typed for #type_path #ty_generics #where_reflect_clause {
fn type_info() -> &'static #bevy_reflect_path::TypeInfo {
#type_info_cell
} }
} }
} }

View File

@ -1,6 +1,6 @@
use crate::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult}; use crate::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult};
use crate::impls::impl_typed; use crate::impls::{impl_type_path, impl_typed};
use crate::utility::WhereClauseOptions; use crate::utility::{extend_where_clause, WhereClauseOptions};
use crate::ReflectMeta; use crate::ReflectMeta;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
@ -8,7 +8,7 @@ use quote::quote;
/// Implements `GetTypeRegistration` and `Reflect` for the given type data. /// Implements `GetTypeRegistration` and `Reflect` for the given type data.
pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream { pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path(); let bevy_reflect_path = meta.bevy_reflect_path();
let type_name = meta.type_name(); let type_path = meta.type_path();
let hash_fn = meta.traits().get_hash_impl(bevy_reflect_path); let hash_fn = meta.traits().get_hash_impl(bevy_reflect_path);
let partial_eq_fn = meta.traits().get_partial_eq_impl(bevy_reflect_path); let partial_eq_fn = meta.traits().get_partial_eq_impl(bevy_reflect_path);
@ -22,27 +22,30 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
#[cfg(not(feature = "documentation"))] #[cfg(not(feature = "documentation"))]
let with_docs: Option<proc_macro2::TokenStream> = None; let with_docs: Option<proc_macro2::TokenStream> = None;
let where_clause_options = WhereClauseOptions::default(); let where_clause_options = WhereClauseOptions::type_path_bounds(meta);
let typed_impl = impl_typed( let typed_impl = impl_typed(
type_name, meta,
meta.generics(),
&where_clause_options, &where_clause_options,
quote! { quote! {
let info = #bevy_reflect_path::ValueInfo::new::<Self>() #with_docs; let info = #bevy_reflect_path::ValueInfo::new::<Self>() #with_docs;
#bevy_reflect_path::TypeInfo::Value(info) #bevy_reflect_path::TypeInfo::Value(info)
}, },
bevy_reflect_path,
); );
let (impl_generics, ty_generics, where_clause) = meta.generics().split_for_impl(); let type_path_impl = impl_type_path(meta, &where_clause_options);
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
let where_reflect_clause = extend_where_clause(where_clause, &where_clause_options);
let get_type_registration_impl = meta.get_type_registration(&where_clause_options); let get_type_registration_impl = meta.get_type_registration(&where_clause_options);
TokenStream::from(quote! { TokenStream::from(quote! {
#get_type_registration_impl #get_type_registration_impl
#type_path_impl
#typed_impl #typed_impl
impl #impl_generics #bevy_reflect_path::Reflect for #type_name #ty_generics #where_clause { impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {
#[inline] #[inline]
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
::core::any::type_name::<Self>() ::core::any::type_name::<Self>()
@ -53,6 +56,11 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info()) #FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> { fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self self

View File

@ -26,20 +26,27 @@ mod impls;
mod reflect_value; mod reflect_value;
mod registration; mod registration;
mod trait_reflection; mod trait_reflection;
mod type_path;
mod type_uuid; mod type_uuid;
mod utility; mod utility;
use crate::derive_data::{ReflectDerive, ReflectMeta, ReflectStruct}; use crate::derive_data::{ReflectDerive, ReflectMeta, ReflectStruct};
use crate::type_uuid::gen_impl_type_uuid; use crate::type_uuid::gen_impl_type_uuid;
use container_attributes::ReflectTraits;
use derive_data::ReflectTypePath;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use reflect_value::ReflectValueDef; use reflect_value::ReflectValueDef;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{parse_macro_input, DeriveInput}; use syn::{parse_macro_input, DeriveInput};
use type_path::NamedTypePathDef;
use type_uuid::TypeUuidDef; use type_uuid::TypeUuidDef;
use utility::WhereClauseOptions;
pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect"; pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value"; pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
pub(crate) static TYPE_PATH_ATTRIBUTE_NAME: &str = "type_path";
pub(crate) static TYPE_NAME_ATTRIBUTE_NAME: &str = "type_name";
/// The main derive macro used by `bevy_reflect` for deriving its `Reflect` trait. /// The main derive macro used by `bevy_reflect` for deriving its `Reflect` trait.
/// ///
@ -52,6 +59,8 @@ pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
/// This macro comes with some helper attributes that can be added to the container item /// This macro comes with some helper attributes that can be added to the container item
/// in order to provide additional functionality or alter the generated implementations. /// in order to provide additional functionality or alter the generated implementations.
/// ///
/// In addition to those listed, this macro can also use the attributes for [`TypePath`] derives.
///
/// ## `#[reflect(Ident)]` /// ## `#[reflect(Ident)]`
/// ///
/// The `#[reflect(Ident)]` attribute is used to add type data registrations to the `GetTypeRegistration` /// The `#[reflect(Ident)]` attribute is used to add type data registrations to the `GetTypeRegistration`
@ -124,7 +133,7 @@ pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
/// which will be used by the reflection serializers to determine whether or not the field is serializable. /// which will be used by the reflection serializers to determine whether or not the field is serializable.
/// ///
/// [`reflect_trait`]: macro@reflect_trait /// [`reflect_trait`]: macro@reflect_trait
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value))] #[proc_macro_derive(Reflect, attributes(reflect, reflect_value, type_path, type_name))]
pub fn derive_reflect(input: TokenStream) -> TokenStream { pub fn derive_reflect(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput); let ast = parse_macro_input!(input as DeriveInput);
@ -188,6 +197,36 @@ pub fn derive_from_reflect(input: TokenStream) -> TokenStream {
} }
} }
/// Derives the `TypePath` trait, providing a stable alternative to [`std::any::type_name`].
///
/// # Container Attributes
///
/// ## `#[type_path = "my_crate::foo"]`
///
/// Optionally specifies a custom module path to use instead of [`module_path`].
///
/// This path does not include the final identifier.
///
/// ## `#[type_name = "RenamedType"]`
///
/// Optionally specifies a new terminating identifier for `TypePath`.
///
/// To use this attribute, `#[type_path = "..."]` must also be specified.
#[proc_macro_derive(TypePath, attributes(type_path, type_name))]
pub fn derive_type_path(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let derive_data = match ReflectDerive::from_input(&ast) {
Ok(data) => data,
Err(err) => return err.into_compile_error().into(),
};
impls::impl_type_path(
derive_data.meta(),
&WhereClauseOptions::type_path_bounds(derive_data.meta()),
)
.into()
}
// From https://github.com/randomPoison/type-uuid // From https://github.com/randomPoison/type-uuid
#[proc_macro_derive(TypeUuid, attributes(uuid))] #[proc_macro_derive(TypeUuid, attributes(uuid))]
pub fn derive_type_uuid(input: TokenStream) -> TokenStream { pub fn derive_type_uuid(input: TokenStream) -> TokenStream {
@ -254,30 +293,47 @@ pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
/// The only reason for this macro's existence is so that `bevy_reflect` can easily implement the reflection traits /// The only reason for this macro's existence is so that `bevy_reflect` can easily implement the reflection traits
/// on primitives and other Rust types internally. /// on primitives and other Rust types internally.
/// ///
/// Since this macro also implements `TypePath`, the type path must be explicit.
/// See [`impl_type_path!`] for the exact syntax.
///
/// # Examples /// # Examples
/// ///
/// Types can be passed with or without registering type data: /// Types can be passed with or without registering type data:
/// ///
/// ```ignore /// ```ignore
/// impl_reflect_value!(foo); /// impl_reflect_value!(::my_crate::Foo);
/// impl_reflect_value!(bar(Debug, Default, Serialize, Deserialize)); /// impl_reflect_value!(::my_crate::Bar(Debug, Default, Serialize, Deserialize));
/// ``` /// ```
/// ///
/// Generic types can also specify their parameters and bounds: /// Generic types can also specify their parameters and bounds:
/// ///
/// ```ignore /// ```ignore
/// impl_reflect_value!(foo<T1, T2: Baz> where T1: Bar (Default, Serialize, Deserialize)); /// impl_reflect_value!(::my_crate::Foo<T1, T2: Baz> where T1: Bar (Default, Serialize, Deserialize));
/// ```
///
/// Custom type paths can be specified:
///
/// ```ignore
/// impl_reflect_value!((in not_my_crate as NotFoo) Foo(Debug, Default));
/// ``` /// ```
/// ///
/// [deriving `Reflect`]: Reflect /// [deriving `Reflect`]: Reflect
#[proc_macro] #[proc_macro]
pub fn impl_reflect_value(input: TokenStream) -> TokenStream { pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input as ReflectValueDef); let def = parse_macro_input!(input as ReflectValueDef);
let meta = ReflectMeta::new(
&def.type_name, let default_name = &def.type_path.segments.last().unwrap().ident;
&def.generics, let type_path = if def.type_path.leading_colon.is_none() && def.custom_path.is_none() {
def.traits.unwrap_or_default(), ReflectTypePath::Primitive(default_name)
); } else {
ReflectTypePath::External {
path: &def.type_path,
custom_path: def.custom_path.map(|path| path.into_path(default_name)),
generics: &def.generics,
}
};
let meta = ReflectMeta::new(type_path, def.traits.unwrap_or_default());
#[cfg(feature = "documentation")] #[cfg(feature = "documentation")]
let meta = meta.with_docs(documentation::Documentation::from_attributes(&def.attrs)); let meta = meta.with_docs(documentation::Documentation::from_attributes(&def.attrs));
@ -294,23 +350,27 @@ pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
/// which have greater functionality. The type being reflected must be in scope, as you cannot /// which have greater functionality. The type being reflected must be in scope, as you cannot
/// qualify it in the macro as e.g. `bevy::prelude::Vec3`. /// qualify it in the macro as e.g. `bevy::prelude::Vec3`.
/// ///
/// It is necessary to add a `#[type_path = "my_crate::foo"]` attribute to all types.
///
/// It may be necessary to add `#[reflect(Default)]` for some types, specifically non-constructible /// It may be necessary to add `#[reflect(Default)]` for some types, specifically non-constructible
/// foreign types. Without `Default` reflected for such types, you will usually get an arcane /// foreign types. Without `Default` reflected for such types, you will usually get an arcane
/// error message and fail to compile. If the type does not implement `Default`, it may not /// error message and fail to compile. If the type does not implement `Default`, it may not
/// be possible to reflect without extending the macro. /// be possible to reflect without extending the macro.
/// ///
///
/// # Example /// # Example
/// Implementing `Reflect` for `bevy::prelude::Vec3` as a struct type: /// Implementing `Reflect` for `bevy::prelude::Vec3` as a struct type:
/// ```ignore /// ```ignore
/// use bevy::prelude::Vec3; /// use bevy::prelude::Vec3;
/// ///
/// impl_reflect_struct!( /// impl_reflect_struct!(
/// #[reflect(PartialEq, Serialize, Deserialize, Default)] /// #[reflect(PartialEq, Serialize, Deserialize, Default)]
/// struct Vec3 { /// #[type_path = "bevy::prelude"]
/// x: f32, /// struct Vec3 {
/// y: f32, /// x: f32,
/// z: f32 /// y: f32,
/// } /// z: f32
/// }
/// ); /// );
/// ``` /// ```
#[proc_macro] #[proc_macro]
@ -323,6 +383,15 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
match derive_data { match derive_data {
ReflectDerive::Struct(struct_data) => { ReflectDerive::Struct(struct_data) => {
if !struct_data.meta().type_path().has_custom_path() {
return syn::Error::new(
struct_data.meta().type_path().span(),
format!("a #[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"] attribute must be specified when using `impl_reflect_struct`")
)
.into_compile_error()
.into();
}
let impl_struct: proc_macro2::TokenStream = impls::impl_struct(&struct_data).into(); let impl_struct: proc_macro2::TokenStream = impls::impl_struct(&struct_data).into();
let impl_from_struct: proc_macro2::TokenStream = let impl_from_struct: proc_macro2::TokenStream =
from_reflect::impl_struct(&struct_data).into(); from_reflect::impl_struct(&struct_data).into();
@ -370,11 +439,84 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
#[proc_macro] #[proc_macro]
pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream { pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input as ReflectValueDef); let def = parse_macro_input!(input as ReflectValueDef);
from_reflect::impl_value(&ReflectMeta::new(
&def.type_name, let default_name = &def.type_path.segments.last().unwrap().ident;
&def.generics, let type_path = if def.type_path.leading_colon.is_none()
def.traits.unwrap_or_default(), && def.custom_path.is_none()
)) && def.generics.params.is_empty()
{
ReflectTypePath::Primitive(default_name)
} else {
ReflectTypePath::External {
path: &def.type_path,
custom_path: def.custom_path.map(|alias| alias.into_path(default_name)),
generics: &def.generics,
}
};
from_reflect::impl_value(&ReflectMeta::new(type_path, def.traits.unwrap_or_default()))
}
/// A replacement for [deriving `TypePath`] for use on foreign types.
///
/// Since (unlike the derive) this macro may be invoked in a different module to where the type is defined,
/// it requires an 'absolute' path definition.
///
/// Specifically, a leading `::` denoting a global path must be specified
/// or a preceeding `(in my_crate::foo)` to specify the custom path must be used.
///
/// # Examples
///
/// Implementing `TypePath` on a foreign type:
/// ```rust,ignore
/// impl_type_path!(::foreign_crate::foo::bar::Baz);
/// ```
///
/// On a generic type:
/// ```rust,ignore
/// impl_type_path!(::foreign_crate::Foo<T>);
/// ```
///
/// On a primitive (note this will not compile for a non-primitive type):
/// ```rust,ignore
/// impl_type_path!(bool);
/// ```
///
/// With a custom type path:
/// ```rust,ignore
/// impl_type_path!((in other_crate::foo::bar) Baz);
/// ```
///
/// With a custom type path and a custom type name:
/// ```rust,ignore
/// impl_type_path!((in other_crate::foo as Baz) Bar);
/// ```
///
/// [deriving `TypePath`]: TypePath
#[proc_macro]
pub fn impl_type_path(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input as NamedTypePathDef);
let type_path = match def {
NamedTypePathDef::External {
ref path,
custom_path,
ref generics,
} => {
let default_name = &path.segments.last().unwrap().ident;
ReflectTypePath::External {
path,
custom_path: custom_path.map(|path| path.into_path(default_name)),
generics,
}
}
NamedTypePathDef::Primtive(ref ident) => ReflectTypePath::Primitive(ident),
};
let meta = ReflectMeta::new(type_path, ReflectTraits::default());
impls::impl_type_path(&meta, &WhereClauseOptions::type_path_bounds(&meta)).into()
} }
/// Derives `TypeUuid` for the given type. This is used internally to implement `TypeUuid` on foreign types, such as those in the std. This macro should be used in the format of `<[Generic Params]> [Type (Path)], [Uuid (String Literal)]`. /// Derives `TypeUuid` for the given type. This is used internally to implement `TypeUuid` on foreign types, such as those in the std. This macro should be used in the format of `<[Generic Params]> [Type (Path)], [Uuid (String Literal)]`.

View File

@ -1,58 +1,59 @@
use crate::container_attributes::ReflectTraits; use crate::container_attributes::ReflectTraits;
use proc_macro2::Ident; use crate::type_path::CustomPathDef;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::token::{Paren, Where}; use syn::token::Paren;
use syn::{parenthesized, Attribute, Generics}; use syn::{parenthesized, Attribute, Generics, Path};
/// A struct used to define a simple reflected value type (such as primitives). /// A struct used to define a simple reflected value type (such as primitives).
/// ///
///
///
/// This takes the form: /// This takes the form:
/// ///
/// ```ignore /// ```ignore
/// // Standard /// // Standard
/// foo(TraitA, TraitB) /// ::my_crate::foo::Bar(TraitA, TraitB)
/// ///
/// // With generics /// // With generics
/// foo<T1: Bar, T2>(TraitA, TraitB) /// ::my_crate::foo::Bar<T1: Bar, T2>(TraitA, TraitB)
/// ///
/// // With generics and where clause /// // With generics and where clause
/// foo<T1, T2> where T1: Bar (TraitA, TraitB) /// ::my_crate::foo::Bar<T1, T2> where T1: Bar (TraitA, TraitB)
///
/// // With a custom path (not with impl_from_reflect_value)
/// (in my_crate::bar) Bar(TraitA, TraitB)
/// ``` /// ```
pub(crate) struct ReflectValueDef { pub(crate) struct ReflectValueDef {
#[allow(dead_code)] #[allow(dead_code)]
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub type_name: Ident, pub type_path: Path,
pub generics: Generics, pub generics: Generics,
pub traits: Option<ReflectTraits>, pub traits: Option<ReflectTraits>,
pub custom_path: Option<CustomPathDef>,
} }
impl Parse for ReflectValueDef { impl Parse for ReflectValueDef {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?; let attrs = input.call(Attribute::parse_outer)?;
let type_ident = input.parse::<Ident>()?;
let generics = input.parse::<Generics>()?; let custom_path = CustomPathDef::parse_parenthesized(input)?;
let mut lookahead = input.lookahead1();
let mut where_clause = None; let type_path = Path::parse_mod_style(input)?;
if lookahead.peek(Where) { let mut generics = input.parse::<Generics>()?;
where_clause = Some(input.parse()?); generics.where_clause = input.parse()?;
lookahead = input.lookahead1();
}
let mut traits = None; let mut traits = None;
if lookahead.peek(Paren) { if input.peek(Paren) {
let content; let content;
parenthesized!(content in input); parenthesized!(content in input);
traits = Some(content.parse::<ReflectTraits>()?); traits = Some(content.parse::<ReflectTraits>()?);
} }
Ok(ReflectValueDef { Ok(ReflectValueDef {
attrs, attrs,
type_name: type_ident, type_path,
generics: Generics { generics,
where_clause,
..generics
},
traits, traits,
custom_path,
}) })
} }
} }

View File

@ -2,21 +2,21 @@
use crate::utility::{extend_where_clause, WhereClauseOptions}; use crate::utility::{extend_where_clause, WhereClauseOptions};
use bit_set::BitSet; use bit_set::BitSet;
use proc_macro2::Ident;
use quote::quote; use quote::quote;
use syn::{Generics, Path};
use crate::derive_data::ReflectMeta;
/// Creates the `GetTypeRegistration` impl for the given type data. /// Creates the `GetTypeRegistration` impl for the given type data.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn impl_get_type_registration( pub(crate) fn impl_get_type_registration(
type_name: &Ident, meta: &ReflectMeta,
bevy_reflect_path: &Path,
registration_data: &[Ident],
generics: &Generics,
where_clause_options: &WhereClauseOptions, where_clause_options: &WhereClauseOptions,
serialization_denylist: Option<&BitSet<u32>>, serialization_denylist: Option<&BitSet<u32>>,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let type_path = meta.type_path();
let bevy_reflect_path = meta.bevy_reflect_path();
let registration_data = meta.traits().idents();
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
let serialization_data = serialization_denylist.map(|denylist| { let serialization_data = serialization_denylist.map(|denylist| {
let denylist = denylist.into_iter(); let denylist = denylist.into_iter();
quote! { quote! {
@ -29,12 +29,12 @@ pub(crate) fn impl_get_type_registration(
quote! { quote! {
#[allow(unused_mut)] #[allow(unused_mut)]
impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_name #ty_generics #where_reflect_clause { impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_path #ty_generics #where_reflect_clause {
fn get_type_registration() -> #bevy_reflect_path::TypeRegistration { fn get_type_registration() -> #bevy_reflect_path::TypeRegistration {
let mut registration = #bevy_reflect_path::TypeRegistration::of::<#type_name #ty_generics>(); let mut registration = #bevy_reflect_path::TypeRegistration::of::<Self>();
registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type()); registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<Self>::from_type());
#serialization_data #serialization_data
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());)* #(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<Self>::from_type());)*
registration registration
} }
} }

View File

@ -0,0 +1,102 @@
use proc_macro2::Ident;
use syn::{
parenthesized,
parse::{Parse, ParseStream},
token::Paren,
Generics, Path, PathSegment, Token,
};
pub(crate) fn parse_path_no_leading_colon(input: ParseStream) -> syn::Result<Path> {
if input.peek(Token![::]) {
return Err(input.error("did not expect a leading double colon (`::`)"));
}
let path = Path::parse_mod_style(input)?;
if path.segments.is_empty() {
Err(input.error("expected a path"))
} else {
Ok(path)
}
}
/// An alias for a `TypePath`.
///
/// This is the parenthesized part of `(in my_crate::foo as MyType) SomeType`.
pub(crate) struct CustomPathDef {
path: Path,
name: Option<Ident>,
}
impl CustomPathDef {
pub fn into_path(mut self, default_name: &Ident) -> Path {
let name = PathSegment::from(self.name.unwrap_or_else(|| default_name.clone()));
self.path.segments.push(name);
self.path
}
pub fn parse_parenthesized(input: ParseStream) -> syn::Result<Option<Self>> {
if input.peek(Paren) {
let path;
parenthesized!(path in input);
Ok(Some(path.call(Self::parse)?))
} else {
Ok(None)
}
}
fn parse(input: ParseStream) -> syn::Result<Self> {
input.parse::<Token![in]>()?;
let custom_path = parse_path_no_leading_colon(input)?;
if !input.peek(Token![as]) {
return Ok(Self {
path: custom_path,
name: None,
});
}
input.parse::<Token![as]>()?;
let custom_name: Ident = input.parse()?;
Ok(Self {
path: custom_path,
name: Some(custom_name),
})
}
}
pub(crate) enum NamedTypePathDef {
External {
path: Path,
generics: Generics,
custom_path: Option<CustomPathDef>,
},
Primtive(Ident),
}
impl Parse for NamedTypePathDef {
fn parse(input: ParseStream) -> syn::Result<Self> {
let custom_path = CustomPathDef::parse_parenthesized(input)?;
let path = Path::parse_mod_style(input)?;
let mut generics = input.parse::<Generics>()?;
generics.where_clause = input.parse()?;
if path.leading_colon.is_none() && custom_path.is_none() {
if path.segments.len() == 1 {
let ident = path.segments.into_iter().next().unwrap().ident;
Ok(NamedTypePathDef::Primtive(ident))
} else {
Err(input.error("non-customized paths must start with a double colon (`::`)"))
}
} else {
Ok(NamedTypePathDef::External {
path,
generics,
custom_path,
})
}
}
}

View File

@ -1,11 +1,11 @@
//! General-purpose utility functions for internal usage within this crate. //! General-purpose utility functions for internal usage within this crate.
use crate::field_attributes::ReflectIgnoreBehavior; use crate::{derive_data::ReflectMeta, field_attributes::ReflectIgnoreBehavior, fq_std::FQOption};
use bevy_macro_utils::BevyManifest; use bevy_macro_utils::BevyManifest;
use bit_set::BitSet; use bit_set::BitSet;
use proc_macro2::{Ident, Span}; use proc_macro2::{Ident, Span};
use quote::quote; use quote::{quote, ToTokens};
use syn::{Member, Path, Type, WhereClause}; use syn::{spanned::Spanned, LitStr, Member, Path, Type, WhereClause};
/// Returns the correct path for `bevy_reflect`. /// Returns the correct path for `bevy_reflect`.
pub(crate) fn get_bevy_reflect_path() -> Path { pub(crate) fn get_bevy_reflect_path() -> Path {
@ -60,6 +60,10 @@ pub(crate) fn ident_or_index(ident: Option<&Ident>, index: usize) -> Member {
/// Options defining how to extend the `where` clause in reflection with any additional bounds needed. /// Options defining how to extend the `where` clause in reflection with any additional bounds needed.
pub(crate) struct WhereClauseOptions { pub(crate) struct WhereClauseOptions {
/// Type parameters that need extra trait bounds.
pub(crate) parameter_types: Box<[Ident]>,
/// Trait bounds to add to the type parameters.
pub(crate) parameter_trait_bounds: proc_macro2::TokenStream,
/// Any types that will be reflected and need an extra trait bound /// Any types that will be reflected and need an extra trait bound
pub(crate) active_types: Box<[Type]>, pub(crate) active_types: Box<[Type]>,
/// Trait bounds to add to the active types /// Trait bounds to add to the active types
@ -70,12 +74,31 @@ pub(crate) struct WhereClauseOptions {
pub(crate) ignored_trait_bounds: proc_macro2::TokenStream, pub(crate) ignored_trait_bounds: proc_macro2::TokenStream,
} }
impl WhereClauseOptions {
/// Extends a where clause, adding a `TypePath` bound to each type parameter.
pub fn type_path_bounds(meta: &ReflectMeta) -> Self {
let bevy_reflect_path = meta.bevy_reflect_path();
Self {
parameter_types: meta
.type_path()
.generics()
.type_params()
.map(|ty| ty.ident.clone())
.collect(),
parameter_trait_bounds: quote! { #bevy_reflect_path::TypePath },
..Default::default()
}
}
}
impl Default for WhereClauseOptions { impl Default for WhereClauseOptions {
/// By default, don't add any additional bounds to the `where` clause /// By default, don't add any additional bounds to the `where` clause
fn default() -> Self { fn default() -> Self {
Self { Self {
parameter_types: Box::new([]),
active_types: Box::new([]), active_types: Box::new([]),
ignored_types: Box::new([]), ignored_types: Box::new([]),
parameter_trait_bounds: quote! {},
active_trait_bounds: quote! {}, active_trait_bounds: quote! {},
ignored_trait_bounds: quote! {}, ignored_trait_bounds: quote! {},
} }
@ -117,22 +140,26 @@ pub(crate) fn extend_where_clause(
where_clause: Option<&WhereClause>, where_clause: Option<&WhereClause>,
where_clause_options: &WhereClauseOptions, where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let parameter_types = &where_clause_options.parameter_types;
let active_types = &where_clause_options.active_types; let active_types = &where_clause_options.active_types;
let ignored_types = &where_clause_options.ignored_types; let ignored_types = &where_clause_options.ignored_types;
let parameter_trait_bounds = &where_clause_options.parameter_trait_bounds;
let active_trait_bounds = &where_clause_options.active_trait_bounds; let active_trait_bounds = &where_clause_options.active_trait_bounds;
let ignored_trait_bounds = &where_clause_options.ignored_trait_bounds; let ignored_trait_bounds = &where_clause_options.ignored_trait_bounds;
let mut generic_where_clause = if let Some(where_clause) = where_clause { let mut generic_where_clause = if let Some(where_clause) = where_clause {
let predicates = where_clause.predicates.iter(); let predicates = where_clause.predicates.iter();
quote! {where #(#predicates,)*} quote! {where #(#predicates,)*}
} else if !(active_types.is_empty() && ignored_types.is_empty()) { } else if !(parameter_types.is_empty() && active_types.is_empty() && ignored_types.is_empty()) {
quote! {where} quote! {where}
} else { } else {
quote! {} quote!()
}; };
generic_where_clause.extend(quote! { generic_where_clause.extend(quote! {
#(#active_types: #active_trait_bounds,)* #(#active_types: #active_trait_bounds,)*
#(#ignored_types: #ignored_trait_bounds,)* #(#ignored_types: #ignored_trait_bounds,)*
// Leave parameter bounds to the end for more sane error messages.
#(#parameter_types: #parameter_trait_bounds,)*
}); });
generic_where_clause generic_where_clause
} }
@ -212,3 +239,118 @@ where
bitset bitset
} }
/// Turns an `Option<TokenStream>` into a `TokenStream` for an `Option`.
pub(crate) fn wrap_in_option(tokens: Option<proc_macro2::TokenStream>) -> proc_macro2::TokenStream {
match tokens {
Some(tokens) => quote! {
#FQOption::Some(#tokens)
},
None => quote! {
#FQOption::None
},
}
}
/// Contains tokens representing different kinds of string.
#[derive(Clone)]
pub(crate) enum StringExpr {
/// A string that is valid at compile time.
///
/// This is either a string literal like `"mystring"`,
/// or a string created by a macro like [`module_path`]
/// or [`concat`].
Const(proc_macro2::TokenStream),
/// A [string slice](str) that is borrowed for a `'static` lifetime.
Borrowed(proc_macro2::TokenStream),
/// An [owned string](String).
Owned(proc_macro2::TokenStream),
}
impl<T: ToString + Spanned> From<T> for StringExpr {
fn from(value: T) -> Self {
Self::from_lit(&LitStr::new(&value.to_string(), value.span()))
}
}
impl StringExpr {
/// Creates a [constant] [`StringExpr`] from a [`struct@LitStr`].
///
/// [constant]: StringExpr::Const
pub fn from_lit(lit: &LitStr) -> Self {
Self::Const(lit.to_token_stream())
}
/// Creates a [constant] [`StringExpr`] by interpreting a [string slice][str] as a [`struct@LitStr`].
///
/// [constant]: StringExpr::Const
pub fn from_str(string: &str) -> Self {
Self::Const(string.into_token_stream())
}
/// Returns tokens for an [owned string](String).
///
/// The returned expression will allocate unless the [`StringExpr`] is [already owned].
///
/// [already owned]: StringExpr::Owned
pub fn into_owned(self) -> proc_macro2::TokenStream {
match self {
Self::Const(tokens) | Self::Borrowed(tokens) => quote! {
::std::string::ToString::to_string(#tokens)
},
Self::Owned(owned) => owned,
}
}
/// Returns tokens for a statically borrowed [string slice](str).
pub fn into_borrowed(self) -> proc_macro2::TokenStream {
match self {
Self::Const(tokens) | Self::Borrowed(tokens) => tokens,
Self::Owned(owned) => quote! {
&#owned
},
}
}
/// Appends a [`StringExpr`] to another.
///
/// If both expressions are [`StringExpr::Const`] this will use [`concat`] to merge them.
pub fn appended_by(mut self, other: StringExpr) -> Self {
if let Self::Const(tokens) = self {
if let Self::Const(more) = other {
return Self::Const(quote! {
::core::concat!(#tokens, #more)
});
}
self = Self::Const(tokens);
}
let owned = self.into_owned();
let borrowed = other.into_borrowed();
Self::Owned(quote! {
#owned + #borrowed
})
}
}
impl Default for StringExpr {
fn default() -> Self {
StringExpr::from_str("")
}
}
impl FromIterator<StringExpr> for StringExpr {
fn from_iter<T: IntoIterator<Item = StringExpr>>(iter: T) -> Self {
let mut iter = iter.into_iter();
match iter.next() {
Some(mut expr) => {
for next in iter {
expr = expr.appended_by(next);
}
expr
}
None => Default::default(),
}
}
}

View File

@ -1,4 +1,9 @@
use crate::{utility::reflect_hasher, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; use bevy_reflect_derive::impl_type_path;
use crate::{
self as bevy_reflect, utility::reflect_hasher, DynamicTypePath, Reflect, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo,
};
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
fmt::Debug, fmt::Debug,
@ -221,6 +226,11 @@ impl Reflect for DynamicArray {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -335,6 +345,7 @@ impl Array for DynamicArray {
} }
} }
impl_type_path!((in bevy_reflect) DynamicArray);
/// An iterator over an [`Array`]. /// An iterator over an [`Array`].
pub struct ArrayIter<'a> { pub struct ArrayIter<'a> {
array: &'a dyn Array, array: &'a dyn Array,

View File

@ -1,6 +1,9 @@
use bevy_reflect_derive::impl_type_path;
use crate::{ use crate::{
enum_debug, enum_hash, enum_partial_eq, DynamicStruct, DynamicTuple, Enum, Reflect, ReflectMut, self as bevy_reflect, enum_debug, enum_hash, enum_partial_eq, DynamicStruct, DynamicTuple,
ReflectOwned, ReflectRef, Struct, Tuple, TypeInfo, VariantFieldIter, VariantType, DynamicTypePath, Enum, Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple, TypeInfo,
VariantFieldIter, VariantType,
}; };
use std::any::Any; use std::any::Any;
use std::fmt::Formatter; use std::fmt::Formatter;
@ -297,6 +300,11 @@ impl Reflect for DynamicEnum {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -420,3 +428,5 @@ impl Reflect for DynamicEnum {
write!(f, ")") write!(f, ")")
} }
} }
impl_type_path!((in bevy_reflect) DynamicEnum);

View File

@ -6,6 +6,7 @@ use glam::*;
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, Hash, PartialEq, Default)] #[reflect(Debug, Hash, PartialEq, Default)]
#[type_path = "glam"]
struct IVec2 { struct IVec2 {
x: i32, x: i32,
y: i32, y: i32,
@ -13,6 +14,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, Hash, PartialEq, Default)] #[reflect(Debug, Hash, PartialEq, Default)]
#[type_path = "glam"]
struct IVec3 { struct IVec3 {
x: i32, x: i32,
y: i32, y: i32,
@ -21,6 +23,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, Hash, PartialEq, Default)] #[reflect(Debug, Hash, PartialEq, Default)]
#[type_path = "glam"]
struct IVec4 { struct IVec4 {
x: i32, x: i32,
y: i32, y: i32,
@ -31,6 +34,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, Hash, PartialEq, Default)] #[reflect(Debug, Hash, PartialEq, Default)]
#[type_path = "glam"]
struct UVec2 { struct UVec2 {
x: u32, x: u32,
y: u32, y: u32,
@ -38,6 +42,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, Hash, PartialEq, Default)] #[reflect(Debug, Hash, PartialEq, Default)]
#[type_path = "glam"]
struct UVec3 { struct UVec3 {
x: u32, x: u32,
y: u32, y: u32,
@ -46,6 +51,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, Hash, PartialEq, Default)] #[reflect(Debug, Hash, PartialEq, Default)]
#[type_path = "glam"]
struct UVec4 { struct UVec4 {
x: u32, x: u32,
y: u32, y: u32,
@ -53,9 +59,9 @@ impl_reflect_struct!(
w: u32, w: u32,
} }
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Vec2 { struct Vec2 {
x: f32, x: f32,
y: f32, y: f32,
@ -63,6 +69,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Vec3 { struct Vec3 {
x: f32, x: f32,
y: f32, y: f32,
@ -71,6 +78,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Vec3A { struct Vec3A {
x: f32, x: f32,
y: f32, y: f32,
@ -79,6 +87,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Vec4 { struct Vec4 {
x: f32, x: f32,
y: f32, y: f32,
@ -89,6 +98,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct BVec2 { struct BVec2 {
x: bool, x: bool,
y: bool, y: bool,
@ -96,6 +106,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct BVec3 { struct BVec3 {
x: bool, x: bool,
y: bool, y: bool,
@ -104,6 +115,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct BVec4 { struct BVec4 {
x: bool, x: bool,
y: bool, y: bool,
@ -114,6 +126,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DVec2 { struct DVec2 {
x: f64, x: f64,
y: f64, y: f64,
@ -121,6 +134,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DVec3 { struct DVec3 {
x: f64, x: f64,
y: f64, y: f64,
@ -129,6 +143,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DVec4 { struct DVec4 {
x: f64, x: f64,
y: f64, y: f64,
@ -139,6 +154,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Mat2 { struct Mat2 {
x_axis: Vec2, x_axis: Vec2,
y_axis: Vec2, y_axis: Vec2,
@ -146,6 +162,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Mat3 { struct Mat3 {
x_axis: Vec3, x_axis: Vec3,
y_axis: Vec3, y_axis: Vec3,
@ -154,6 +171,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Mat3A { struct Mat3A {
x_axis: Vec3A, x_axis: Vec3A,
y_axis: Vec3A, y_axis: Vec3A,
@ -162,6 +180,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Mat4 { struct Mat4 {
x_axis: Vec4, x_axis: Vec4,
y_axis: Vec4, y_axis: Vec4,
@ -172,6 +191,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DMat2 { struct DMat2 {
x_axis: DVec2, x_axis: DVec2,
y_axis: DVec2, y_axis: DVec2,
@ -179,6 +199,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DMat3 { struct DMat3 {
x_axis: DVec3, x_axis: DVec3,
y_axis: DVec3, y_axis: DVec3,
@ -187,6 +208,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DMat4 { struct DMat4 {
x_axis: DVec4, x_axis: DVec4,
y_axis: DVec4, y_axis: DVec4,
@ -197,6 +219,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Affine2 { struct Affine2 {
matrix2: Mat2, matrix2: Mat2,
translation: Vec2, translation: Vec2,
@ -204,6 +227,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct Affine3A { struct Affine3A {
matrix3: Mat3A, matrix3: Mat3A,
translation: Vec3A, translation: Vec3A,
@ -212,6 +236,7 @@ impl_reflect_struct!(
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DAffine2 { struct DAffine2 {
matrix2: DMat2, matrix2: DMat2,
translation: DVec2, translation: DVec2,
@ -219,6 +244,7 @@ impl_reflect_struct!(
); );
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Default)] #[reflect(Debug, PartialEq, Default)]
#[type_path = "glam"]
struct DAffine3 { struct DAffine3 {
matrix3: DMat3, matrix3: DMat3,
translation: DVec3, translation: DVec3,
@ -229,12 +255,24 @@ impl_reflect_struct!(
// mechanisms for read-only fields. I doubt those mechanisms would be added, // mechanisms for read-only fields. I doubt those mechanisms would be added,
// so for now quaternions will remain as values. They are represented identically // so for now quaternions will remain as values. They are represented identically
// to Vec4 and DVec4, so you may use those instead and convert between. // to Vec4 and DVec4, so you may use those instead and convert between.
impl_reflect_value!(Quat(Debug, PartialEq, Serialize, Deserialize, Default)); impl_reflect_value!(::glam::Quat(
impl_reflect_value!(DQuat(Debug, PartialEq, Serialize, Deserialize, Default)); Debug,
PartialEq,
Serialize,
Deserialize,
Default
));
impl_reflect_value!(::glam::DQuat(
Debug,
PartialEq,
Serialize,
Deserialize,
Default
));
impl_from_reflect_value!(Quat); impl_from_reflect_value!(Quat);
impl_from_reflect_value!(DQuat); impl_from_reflect_value!(DQuat);
impl_reflect_value!(EulerRot(Debug, Default)); impl_reflect_value!(::glam::EulerRot(Debug, Default));
impl_reflect_value!(BVec3A(Debug, Default)); impl_reflect_value!(::glam::BVec3A(Debug, Default));
impl_reflect_value!(BVec4A(Debug, Default)); impl_reflect_value!(::glam::BVec4A(Debug, Default));

View File

@ -6,6 +6,7 @@ use bevy_reflect_derive::impl_reflect_struct;
impl_reflect_struct!( impl_reflect_struct!(
#[reflect(Debug, PartialEq, Serialize, Deserialize, Default)] #[reflect(Debug, PartialEq, Serialize, Deserialize, Default)]
#[type_path = "bevy_math"]
struct Rect { struct Rect {
min: Vec2, min: Vec2,
max: Vec2, max: Vec2,

View File

@ -1,13 +1,15 @@
use bevy_reflect_derive::impl_type_path;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::any::Any; use std::any::Any;
use crate::utility::GenericTypeInfoCell; use crate::utility::GenericTypeInfoCell;
use crate::{ use crate::{
FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Reflect, ReflectFromPtr, self as bevy_reflect, DynamicTypePath, FromReflect, FromType, GetTypeRegistration, List,
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeRegistration, Typed, ListInfo, ListIter, Reflect, ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo,
TypePath, TypeRegistration, Typed,
}; };
impl<T: smallvec::Array + Send + Sync + 'static> List for SmallVec<T> impl<T: smallvec::Array + TypePath + Send + Sync> List for SmallVec<T>
where where
T::Item: FromReflect, T::Item: FromReflect,
{ {
@ -74,7 +76,7 @@ where
} }
} }
impl<T: smallvec::Array + Send + Sync + 'static> Reflect for SmallVec<T> impl<T: smallvec::Array + TypePath + Send + Sync> Reflect for SmallVec<T>
where where
T::Item: FromReflect, T::Item: FromReflect,
{ {
@ -86,6 +88,11 @@ where
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -140,7 +147,7 @@ where
} }
} }
impl<T: smallvec::Array + Send + Sync + 'static> Typed for SmallVec<T> impl<T: smallvec::Array + TypePath + Send + Sync + 'static> Typed for SmallVec<T>
where where
T::Item: FromReflect, T::Item: FromReflect,
{ {
@ -150,7 +157,9 @@ where
} }
} }
impl<T: smallvec::Array + Send + Sync + 'static> FromReflect for SmallVec<T> impl_type_path!(::smallvec::SmallVec<T: smallvec::Array + TypePath + Send + Sync>);
impl<T: smallvec::Array + TypePath + Send + Sync> FromReflect for SmallVec<T>
where where
T::Item: FromReflect, T::Item: FromReflect,
{ {
@ -167,7 +176,7 @@ where
} }
} }
impl<T: smallvec::Array + Send + Sync + 'static> GetTypeRegistration for SmallVec<T> impl<T: smallvec::Array + TypePath + Send + Sync> GetTypeRegistration for SmallVec<T>
where where
T::Item: FromReflect, T::Item: FromReflect,
{ {

View File

@ -1,14 +1,16 @@
use crate::std_traits::ReflectDefault; use crate::std_traits::ReflectDefault;
use crate::{self as bevy_reflect, ReflectFromPtr, ReflectFromReflect, ReflectOwned}; use crate::{self as bevy_reflect, ReflectFromPtr, ReflectFromReflect, ReflectOwned};
use crate::{ use crate::{
map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum, DynamicMap, Enum, impl_type_path, map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum,
EnumInfo, FromReflect, FromType, GetTypeRegistration, List, ListInfo, Map, MapInfo, MapIter, DynamicMap, DynamicTypePath, Enum, EnumInfo, FromReflect, FromType, GetTypeRegistration, List,
Reflect, ReflectDeserialize, ReflectMut, ReflectRef, ReflectSerialize, TupleVariantInfo, ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef,
TypeInfo, TypeRegistration, Typed, UnitVariantInfo, UnnamedField, ValueInfo, VariantFieldIter, ReflectSerialize, TupleVariantInfo, TypeInfo, TypePath, TypeRegistration, Typed,
VariantInfo, VariantType, UnitVariantInfo, UnnamedField, ValueInfo, VariantFieldIter, VariantInfo, VariantType,
}; };
use crate::utility::{reflect_hasher, GenericTypeInfoCell, NonGenericTypeInfoCell}; use crate::utility::{
reflect_hasher, GenericTypeInfoCell, GenericTypePathCell, NonGenericTypeInfoCell,
};
use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value};
use bevy_utils::HashSet; use bevy_utils::HashSet;
use bevy_utils::{Duration, Instant}; use bevy_utils::{Duration, Instant};
@ -93,7 +95,7 @@ impl_reflect_value!(String(
Deserialize, Deserialize,
Default Default
)); ));
impl_reflect_value!(PathBuf( impl_reflect_value!(::std::path::PathBuf(
Debug, Debug,
Hash, Hash,
PartialEq, PartialEq,
@ -101,15 +103,18 @@ impl_reflect_value!(PathBuf(
Deserialize, Deserialize,
Default Default
)); ));
impl_reflect_value!(Result<T: Clone + Reflect + 'static, E: Clone + Reflect + 'static>()); impl_reflect_value!(
impl_reflect_value!(HashSet<T: Hash + Eq + Clone + Send + Sync + 'static>()); ::core::result::Result < T: Clone + Reflect + TypePath,
impl_reflect_value!(Range<T: Clone + Send + Sync + 'static>()); E: Clone + Reflect + TypePath > ()
impl_reflect_value!(RangeInclusive<T: Clone + Send + Sync + 'static>()); );
impl_reflect_value!(RangeFrom<T: Clone + Send + Sync + 'static>()); impl_reflect_value!(::bevy_utils::HashSet<T: Hash + Eq + Clone + Send + Sync>());
impl_reflect_value!(RangeTo<T: Clone + Send + Sync + 'static>()); impl_reflect_value!(::core::ops::Range<T: Clone + Send + Sync>());
impl_reflect_value!(RangeToInclusive<T: Clone + Send + Sync + 'static>()); impl_reflect_value!(::core::ops::RangeInclusive<T: Clone + Send + Sync>());
impl_reflect_value!(RangeFull()); impl_reflect_value!(::core::ops::RangeFrom<T: Clone + Send + Sync>());
impl_reflect_value!(Duration( impl_reflect_value!(::core::ops::RangeTo<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeToInclusive<T: Clone + Send + Sync>());
impl_reflect_value!(::core::ops::RangeFull());
impl_reflect_value!(::bevy_utils::Duration(
Debug, Debug,
Hash, Hash,
PartialEq, PartialEq,
@ -117,26 +122,104 @@ impl_reflect_value!(Duration(
Deserialize, Deserialize,
Default Default
)); ));
impl_reflect_value!(Instant(Debug, Hash, PartialEq)); impl_reflect_value!(::bevy_utils::Instant(Debug, Hash, PartialEq));
impl_reflect_value!(NonZeroI128(Debug, Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(::core::num::NonZeroI128(
impl_reflect_value!(NonZeroU128(Debug, Hash, PartialEq, Serialize, Deserialize)); Debug,
impl_reflect_value!(NonZeroIsize(Debug, Hash, PartialEq, Serialize, Deserialize)); Hash,
impl_reflect_value!(NonZeroUsize(Debug, Hash, PartialEq, Serialize, Deserialize)); PartialEq,
impl_reflect_value!(NonZeroI64(Debug, Hash, PartialEq, Serialize, Deserialize)); Serialize,
impl_reflect_value!(NonZeroU64(Debug, Hash, PartialEq, Serialize, Deserialize)); Deserialize
impl_reflect_value!(NonZeroU32(Debug, Hash, PartialEq, Serialize, Deserialize)); ));
impl_reflect_value!(NonZeroI32(Debug, Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(::core::num::NonZeroU128(
impl_reflect_value!(NonZeroI16(Debug, Hash, PartialEq, Serialize, Deserialize)); Debug,
impl_reflect_value!(NonZeroU16(Debug, Hash, PartialEq, Serialize, Deserialize)); Hash,
impl_reflect_value!(NonZeroU8(Debug, Hash, PartialEq, Serialize, Deserialize)); PartialEq,
impl_reflect_value!(NonZeroI8(Debug, Hash, PartialEq, Serialize, Deserialize)); Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroIsize(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroUsize(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI64(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU64(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU32(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI32(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI16(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU16(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroU8(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
impl_reflect_value!(::core::num::NonZeroI8(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
// `Serialize` and `Deserialize` only for platforms supported by serde: // `Serialize` and `Deserialize` only for platforms supported by serde:
// https://github.com/serde-rs/serde/blob/3ffb86fc70efd3d329519e2dddfa306cc04f167c/serde/src/de/impls.rs#L1732 // https://github.com/serde-rs/serde/blob/3ffb86fc70efd3d329519e2dddfa306cc04f167c/serde/src/de/impls.rs#L1732
#[cfg(any(unix, windows))] #[cfg(any(unix, windows))]
impl_reflect_value!(OsString(Debug, Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(::std::ffi::OsString(
Debug,
Hash,
PartialEq,
Serialize,
Deserialize
));
#[cfg(not(any(unix, windows)))] #[cfg(not(any(unix, windows)))]
impl_reflect_value!(OsString(Debug, Hash, PartialEq)); impl_reflect_value!(::std::ffi::OsString(Debug, Hash, PartialEq));
impl_from_reflect_value!(bool); impl_from_reflect_value!(bool);
impl_from_reflect_value!(char); impl_from_reflect_value!(char);
@ -157,12 +240,12 @@ impl_from_reflect_value!(f64);
impl_from_reflect_value!(String); impl_from_reflect_value!(String);
impl_from_reflect_value!(PathBuf); impl_from_reflect_value!(PathBuf);
impl_from_reflect_value!(OsString); impl_from_reflect_value!(OsString);
impl_from_reflect_value!(HashSet<T: Hash + Eq + Clone + Send + Sync + 'static>); impl_from_reflect_value!(HashSet<T: TypePath + Hash + Eq + Clone + Send + Sync>);
impl_from_reflect_value!(Range<T: Clone + Send + Sync + 'static>); impl_from_reflect_value!(Range<T: TypePath + Clone + Send + Sync>);
impl_from_reflect_value!(RangeInclusive<T: Clone + Send + Sync + 'static>); impl_from_reflect_value!(RangeInclusive<T: TypePath + Clone + Send + Sync>);
impl_from_reflect_value!(RangeFrom<T: Clone + Send + Sync + 'static>); impl_from_reflect_value!(RangeFrom<T: TypePath + Clone + Send + Sync>);
impl_from_reflect_value!(RangeTo<T: Clone + Send + Sync + 'static>); impl_from_reflect_value!(RangeTo<T: TypePath + Clone + Send + Sync>);
impl_from_reflect_value!(RangeToInclusive<T: Clone + Send + Sync + 'static>); impl_from_reflect_value!(RangeToInclusive<T: TypePath + Clone + Send + Sync>);
impl_from_reflect_value!(RangeFull); impl_from_reflect_value!(RangeFull);
impl_from_reflect_value!(Duration); impl_from_reflect_value!(Duration);
impl_from_reflect_value!(Instant); impl_from_reflect_value!(Instant);
@ -180,8 +263,8 @@ impl_from_reflect_value!(NonZeroU8);
impl_from_reflect_value!(NonZeroI8); impl_from_reflect_value!(NonZeroI8);
macro_rules! impl_reflect_for_veclike { macro_rules! impl_reflect_for_veclike {
($ty:ty, $insert:expr, $remove:expr, $push:expr, $pop:expr, $sub:ty) => { ($ty:path, $insert:expr, $remove:expr, $push:expr, $pop:expr, $sub:ty) => {
impl<T: FromReflect> List for $ty { impl<T: FromReflect + TypePath> List for $ty {
#[inline] #[inline]
fn get(&self, index: usize) -> Option<&dyn Reflect> { fn get(&self, index: usize) -> Option<&dyn Reflect> {
<$sub>::get(self, index).map(|value| value as &dyn Reflect) <$sub>::get(self, index).map(|value| value as &dyn Reflect)
@ -228,8 +311,8 @@ macro_rules! impl_reflect_for_veclike {
} }
#[inline] #[inline]
fn iter(&self) -> $crate::ListIter { fn iter(&self) -> ListIter {
$crate::ListIter::new(self) ListIter::new(self)
} }
#[inline] #[inline]
@ -240,7 +323,7 @@ macro_rules! impl_reflect_for_veclike {
} }
} }
impl<T: FromReflect> Reflect for $ty { impl<T: FromReflect + TypePath> Reflect for $ty {
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
} }
@ -249,6 +332,11 @@ macro_rules! impl_reflect_for_veclike {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -307,14 +395,16 @@ macro_rules! impl_reflect_for_veclike {
} }
} }
impl<T: FromReflect> Typed for $ty { impl<T: FromReflect + TypePath> Typed for $ty {
fn type_info() -> &'static TypeInfo { fn type_info() -> &'static TypeInfo {
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| TypeInfo::List(ListInfo::new::<Self, T>())) CELL.get_or_insert::<Self, _>(|| TypeInfo::List(ListInfo::new::<Self, T>()))
} }
} }
impl<T: FromReflect> GetTypeRegistration for $ty { impl_type_path!($ty where T: FromReflect);
impl<T: FromReflect + TypePath> GetTypeRegistration for $ty {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<$ty>(); let mut registration = TypeRegistration::of::<$ty>();
registration.insert::<ReflectFromPtr>(FromType::<$ty>::from_type()); registration.insert::<ReflectFromPtr>(FromType::<$ty>::from_type());
@ -322,7 +412,7 @@ macro_rules! impl_reflect_for_veclike {
} }
} }
impl<T: FromReflect> FromReflect for $ty { impl<T: FromReflect + TypePath> FromReflect for $ty {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> { fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
if let ReflectRef::List(ref_list) = reflect.reflect_ref() { if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
let mut new_list = Self::with_capacity(ref_list.len()); let mut new_list = Self::with_capacity(ref_list.len());
@ -338,9 +428,16 @@ macro_rules! impl_reflect_for_veclike {
}; };
} }
impl_reflect_for_veclike!(Vec<T>, Vec::insert, Vec::remove, Vec::push, Vec::pop, [T]);
impl_reflect_for_veclike!( impl_reflect_for_veclike!(
VecDeque<T>, ::alloc::vec::Vec<T>,
Vec::insert,
Vec::remove,
Vec::push,
Vec::pop,
[T]
);
impl_reflect_for_veclike!(
::alloc::collections::VecDeque<T>,
VecDeque::insert, VecDeque::insert,
VecDeque::remove, VecDeque::remove,
VecDeque::push_back, VecDeque::push_back,
@ -349,12 +446,12 @@ impl_reflect_for_veclike!(
); );
macro_rules! impl_reflect_for_hashmap { macro_rules! impl_reflect_for_hashmap {
($ty:ty) => { ($ty:path) => {
impl<K, V, S> Map for $ty impl<K, V, S> Map for $ty
where where
K: FromReflect + Eq + Hash, K: FromReflect + TypePath + Eq + Hash,
V: FromReflect, V: FromReflect + TypePath,
S: BuildHasher + Send + Sync + 'static, S: TypePath + BuildHasher + Send + Sync,
{ {
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> { fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
key.downcast_ref::<K>() key.downcast_ref::<K>()
@ -446,9 +543,9 @@ macro_rules! impl_reflect_for_hashmap {
impl<K, V, S> Reflect for $ty impl<K, V, S> Reflect for $ty
where where
K: FromReflect + Eq + Hash, K: FromReflect + TypePath + Eq + Hash,
V: FromReflect, V: FromReflect + TypePath,
S: BuildHasher + Send + Sync + 'static, S: TypePath + BuildHasher + Send + Sync,
{ {
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
@ -458,6 +555,10 @@ macro_rules! impl_reflect_for_hashmap {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -515,9 +616,9 @@ macro_rules! impl_reflect_for_hashmap {
impl<K, V, S> Typed for $ty impl<K, V, S> Typed for $ty
where where
K: FromReflect + Eq + Hash, K: FromReflect + TypePath + Eq + Hash,
V: FromReflect, V: FromReflect + TypePath,
S: BuildHasher + Send + Sync + 'static, S: TypePath + BuildHasher + Send + Sync,
{ {
fn type_info() -> &'static TypeInfo { fn type_info() -> &'static TypeInfo {
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
@ -527,9 +628,9 @@ macro_rules! impl_reflect_for_hashmap {
impl<K, V, S> GetTypeRegistration for $ty impl<K, V, S> GetTypeRegistration for $ty
where where
K: FromReflect + Eq + Hash, K: FromReflect + TypePath + Eq + Hash,
V: FromReflect, V: FromReflect + TypePath,
S: BuildHasher + Send + Sync + 'static, S: TypePath + BuildHasher + Send + Sync,
{ {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<Self>(); let mut registration = TypeRegistration::of::<Self>();
@ -540,9 +641,9 @@ macro_rules! impl_reflect_for_hashmap {
impl<K, V, S> FromReflect for $ty impl<K, V, S> FromReflect for $ty
where where
K: FromReflect + Eq + Hash, K: FromReflect + TypePath + Eq + Hash,
V: FromReflect, V: FromReflect + TypePath,
S: BuildHasher + Default + Send + Sync + 'static, S: TypePath + BuildHasher + Default + Send + Sync,
{ {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> { fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
if let ReflectRef::Map(ref_map) = reflect.reflect_ref() { if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
@ -561,10 +662,27 @@ macro_rules! impl_reflect_for_hashmap {
}; };
} }
impl_reflect_for_hashmap!(bevy_utils::hashbrown::HashMap<K, V, S>); impl_reflect_for_hashmap!(::std::collections::HashMap<K, V, S>);
impl_reflect_for_hashmap!(std::collections::HashMap<K, V, S>); impl_type_path!(::std::collections::hash_map::RandomState);
impl_type_path!(
::std::collections::HashMap<K, V, S>
where
K: FromReflect + Eq + Hash + ?Sized,
V: FromReflect + ?Sized,
S: BuildHasher + Send + Sync + 'static,
);
impl<T: Reflect, const N: usize> Array for [T; N] { impl_reflect_for_hashmap!(bevy_utils::hashbrown::HashMap<K, V, S>);
impl_type_path!(::bevy_utils::hashbrown::hash_map::DefaultHashBuilder);
impl_type_path!(
::bevy_utils::hashbrown::HashMap<K, V, S>
where
K: FromReflect + Eq + Hash + ?Sized,
V: FromReflect + ?Sized,
S: BuildHasher + Send + Sync + 'static,
);
impl<T: Reflect + TypePath, const N: usize> Array for [T; N] {
#[inline] #[inline]
fn get(&self, index: usize) -> Option<&dyn Reflect> { fn get(&self, index: usize) -> Option<&dyn Reflect> {
<[T]>::get(self, index).map(|value| value as &dyn Reflect) <[T]>::get(self, index).map(|value| value as &dyn Reflect)
@ -593,7 +711,7 @@ impl<T: Reflect, const N: usize> Array for [T; N] {
} }
} }
impl<T: Reflect, const N: usize> Reflect for [T; N] { impl<T: Reflect + TypePath, const N: usize> Reflect for [T; N] {
#[inline] #[inline]
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
@ -603,6 +721,11 @@ impl<T: Reflect, const N: usize> Reflect for [T; N] {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -675,7 +798,7 @@ impl<T: Reflect, const N: usize> Reflect for [T; N] {
} }
} }
impl<T: FromReflect, const N: usize> FromReflect for [T; N] { impl<T: FromReflect + TypePath, const N: usize> FromReflect for [T; N] {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> { fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
if let ReflectRef::Array(ref_array) = reflect.reflect_ref() { if let ReflectRef::Array(ref_array) = reflect.reflect_ref() {
let mut temp_vec = Vec::with_capacity(ref_array.len()); let mut temp_vec = Vec::with_capacity(ref_array.len());
@ -689,13 +812,25 @@ impl<T: FromReflect, const N: usize> FromReflect for [T; N] {
} }
} }
impl<T: Reflect, const N: usize> Typed for [T; N] { impl<T: Reflect + TypePath, const N: usize> Typed for [T; N] {
fn type_info() -> &'static TypeInfo { fn type_info() -> &'static TypeInfo {
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| TypeInfo::Array(ArrayInfo::new::<Self, T>(N))) CELL.get_or_insert::<Self, _>(|| TypeInfo::Array(ArrayInfo::new::<Self, T>(N)))
} }
} }
impl<T: Reflect + TypePath, const N: usize> TypePath for [T; N] {
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| format!("[{t}; {N}]", t = T::type_path()))
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| format!("[{t}; {N}]", t = T::short_type_path()))
}
}
// TODO: // TODO:
// `FromType::from_type` requires `Deserialize<'de>` to be implemented for `T`. // `FromType::from_type` requires `Deserialize<'de>` to be implemented for `T`.
// Currently serde only supports `Deserialize<'de>` for arrays up to size 32. // Currently serde only supports `Deserialize<'de>` for arrays up to size 32.
@ -704,7 +839,7 @@ impl<T: Reflect, const N: usize> Typed for [T; N] {
macro_rules! impl_array_get_type_registration { macro_rules! impl_array_get_type_registration {
($($N:expr)+) => { ($($N:expr)+) => {
$( $(
impl<T: Reflect > GetTypeRegistration for [T; $N] { impl<T: Reflect + TypePath> GetTypeRegistration for [T; $N] {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
TypeRegistration::of::<[T; $N]>() TypeRegistration::of::<[T; $N]>()
} }
@ -720,13 +855,13 @@ impl_array_get_type_registration! {
30 31 32 30 31 32
} }
impl<T: FromReflect> GetTypeRegistration for Option<T> { impl<T: FromReflect + TypePath> GetTypeRegistration for Option<T> {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
TypeRegistration::of::<Option<T>>() TypeRegistration::of::<Option<T>>()
} }
} }
impl<T: FromReflect> Enum for Option<T> { impl<T: FromReflect + TypePath> Enum for Option<T> {
fn field(&self, _name: &str) -> Option<&dyn Reflect> { fn field(&self, _name: &str) -> Option<&dyn Reflect> {
None None
} }
@ -797,7 +932,7 @@ impl<T: FromReflect> Enum for Option<T> {
} }
} }
impl<T: FromReflect> Reflect for Option<T> { impl<T: FromReflect + TypePath> Reflect for Option<T> {
#[inline] #[inline]
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
@ -808,6 +943,11 @@ impl<T: FromReflect> Reflect for Option<T> {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -911,7 +1051,7 @@ impl<T: FromReflect> Reflect for Option<T> {
} }
} }
impl<T: FromReflect> FromReflect for Option<T> { impl<T: FromReflect + TypePath> FromReflect for Option<T> {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> { fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
if let ReflectRef::Enum(dyn_enum) = reflect.reflect_ref() { if let ReflectRef::Enum(dyn_enum) = reflect.reflect_ref() {
match dyn_enum.variant_name() { match dyn_enum.variant_name() {
@ -949,7 +1089,7 @@ impl<T: FromReflect> FromReflect for Option<T> {
} }
} }
impl<T: FromReflect> Typed for Option<T> { impl<T: FromReflect + TypePath> Typed for Option<T> {
fn type_info() -> &'static TypeInfo { fn type_info() -> &'static TypeInfo {
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| { CELL.get_or_insert::<Self, _>(|| {
@ -964,6 +1104,8 @@ impl<T: FromReflect> Typed for Option<T> {
} }
} }
impl_type_path!(::core::option::Option<T: FromReflect + TypePath>);
impl Reflect for Cow<'static, str> { impl Reflect for Cow<'static, str> {
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
@ -973,6 +1115,11 @@ impl Reflect for Cow<'static, str> {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -1051,6 +1198,30 @@ impl Typed for Cow<'static, str> {
} }
} }
impl TypePath for Cow<'static, str> {
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| "std::borrow::Cow::<str>".to_owned())
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| "Cow<str>".to_owned())
}
fn type_ident() -> Option<&'static str> {
Some("Cow")
}
fn crate_name() -> Option<&'static str> {
Some("std")
}
fn module_path() -> Option<&'static str> {
Some("std::borrow")
}
}
impl GetTypeRegistration for Cow<'static, str> { impl GetTypeRegistration for Cow<'static, str> {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<Cow<'static, str>>(); let mut registration = TypeRegistration::of::<Cow<'static, str>>();
@ -1081,6 +1252,11 @@ impl Reflect for &'static Path {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -1159,6 +1335,18 @@ impl Typed for &'static Path {
} }
} }
impl TypePath for &'static Path {
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| "&std::path::Path".to_owned())
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| "&Path".to_owned())
}
}
impl GetTypeRegistration for &'static Path { impl GetTypeRegistration for &'static Path {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<Self>(); let mut registration = TypeRegistration::of::<Self>();
@ -1178,6 +1366,11 @@ impl Reflect for Cow<'static, Path> {
std::any::type_name::<Self>() std::any::type_name::<Self>()
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
@ -1264,6 +1457,11 @@ impl Typed for Cow<'static, Path> {
} }
} }
trait PathOnly: ToOwned {}
impl PathOnly for Path {}
impl_type_path!(::alloc::borrow::Cow<'a: 'static, T: PathOnly + ?Sized>);
impl_type_path!(::std::path::Path);
impl FromReflect for Cow<'static, Path> { impl FromReflect for Cow<'static, Path> {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> { fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
Some(reflect.as_any().downcast_ref::<Self>()?.clone()) Some(reflect.as_any().downcast_ref::<Self>()?.clone())

View File

@ -448,6 +448,7 @@ mod struct_trait;
mod tuple; mod tuple;
mod tuple_struct; mod tuple_struct;
mod type_info; mod type_info;
mod type_path;
mod type_registry; mod type_registry;
mod type_uuid; mod type_uuid;
mod type_uuid_impl; mod type_uuid_impl;
@ -496,12 +497,15 @@ pub use struct_trait::*;
pub use tuple::*; pub use tuple::*;
pub use tuple_struct::*; pub use tuple_struct::*;
pub use type_info::*; pub use type_info::*;
pub use type_path::*;
pub use type_registry::*; pub use type_registry::*;
pub use type_uuid::*; pub use type_uuid::*;
pub use bevy_reflect_derive::*; pub use bevy_reflect_derive::*;
pub use erased_serde; pub use erased_serde;
extern crate alloc;
#[doc(hidden)] #[doc(hidden)]
pub mod __macro_exports { pub mod __macro_exports {
use crate::Uuid; use crate::Uuid;
@ -543,8 +547,8 @@ mod tests {
ser::{to_string_pretty, PrettyConfig}, ser::{to_string_pretty, PrettyConfig},
Deserializer, Deserializer,
}; };
use std::any::TypeId;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::{any::TypeId, marker::PhantomData};
use super::prelude::*; use super::prelude::*;
use super::*; use super::*;
@ -1118,6 +1122,98 @@ mod tests {
); );
} }
#[test]
fn reflect_type_path() {
#[derive(TypePath)]
struct Param;
#[derive(TypePath)]
struct Derive;
#[derive(TypePath)]
#[type_path = "my_alias"]
struct DerivePath;
#[derive(TypePath)]
#[type_path = "my_alias"]
#[type_name = "MyDerivePathName"]
struct DerivePathName;
#[derive(TypePath)]
struct DeriveG<T>(PhantomData<T>);
#[derive(TypePath)]
#[type_path = "my_alias"]
struct DerivePathG<T, const N: usize>(PhantomData<T>);
#[derive(TypePath)]
#[type_path = "my_alias"]
#[type_name = "MyDerivePathNameG"]
struct DerivePathNameG<T>(PhantomData<T>);
struct Macro;
impl_type_path!((in my_alias) Macro);
struct MacroName;
impl_type_path!((in my_alias as MyMacroName) MacroName);
struct MacroG<T, const N: usize>(PhantomData<T>);
impl_type_path!((in my_alias) MacroG<T, const N: usize>);
struct MacroNameG<T>(PhantomData<T>);
impl_type_path!((in my_alias as MyMacroNameG) MacroNameG<T>);
assert_eq!(Derive::type_path(), "bevy_reflect::tests::Derive");
assert_eq!(DerivePath::type_path(), "my_alias::DerivePath");
assert_eq!(DerivePathName::type_path(), "my_alias::MyDerivePathName");
assert_eq!(
DeriveG::<Param>::type_path(),
"bevy_reflect::tests::DeriveG<bevy_reflect::tests::Param>"
);
assert_eq!(
DerivePathG::<Param, 10>::type_path(),
"my_alias::DerivePathG<bevy_reflect::tests::Param, 10>"
);
assert_eq!(
DerivePathNameG::<Param>::type_path(),
"my_alias::MyDerivePathNameG<bevy_reflect::tests::Param>"
);
assert_eq!(Macro::type_path(), "my_alias::Macro");
assert_eq!(MacroName::type_path(), "my_alias::MyMacroName");
assert_eq!(
MacroG::<Param, 10>::type_path(),
"my_alias::MacroG<bevy_reflect::tests::Param, 10>"
);
assert_eq!(
MacroNameG::<Param>::type_path(),
"my_alias::MyMacroNameG<bevy_reflect::tests::Param>"
);
assert_eq!(Derive::short_type_path(), "Derive");
assert_eq!(DerivePath::short_type_path(), "DerivePath");
assert_eq!(DerivePathName::short_type_path(), "MyDerivePathName");
assert_eq!(DeriveG::<Param>::short_type_path(), "DeriveG<Param>");
assert_eq!(
DerivePathG::<Param, 10>::short_type_path(),
"DerivePathG<Param, 10>"
);
assert_eq!(
DerivePathNameG::<Param>::short_type_path(),
"MyDerivePathNameG<Param>"
);
assert_eq!(Macro::short_type_path(), "Macro");
assert_eq!(MacroName::short_type_path(), "MyMacroName");
assert_eq!(MacroG::<Param, 10>::short_type_path(), "MacroG<Param, 10>");
assert_eq!(
MacroNameG::<Param>::short_type_path(),
"MyMacroNameG<Param>"
);
}
#[test] #[test]
fn reflect_type_info() { fn reflect_type_info() {
// TypeInfo // TypeInfo
@ -1171,7 +1267,7 @@ mod tests {
// Struct (generic) // Struct (generic)
#[derive(Reflect)] #[derive(Reflect)]
struct MyGenericStruct<T: Reflect> { struct MyGenericStruct<T: Reflect + TypePath> {
foo: T, foo: T,
bar: usize, bar: usize,
} }
@ -1420,7 +1516,7 @@ mod tests {
struct SomePrimitive; struct SomePrimitive;
impl_reflect_value!( impl_reflect_value!(
/// Some primitive for which we have attributed custom documentation. /// Some primitive for which we have attributed custom documentation.
SomePrimitive (in bevy_reflect::tests) SomePrimitive
); );
let info = <SomePrimitive as Typed>::type_info(); let info = <SomePrimitive as Typed>::type_info();

View File

@ -2,8 +2,13 @@ use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use bevy_reflect_derive::impl_type_path;
use crate::utility::reflect_hasher; use crate::utility::reflect_hasher;
use crate::{FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; use crate::{
self as bevy_reflect, DynamicTypePath, FromReflect, Reflect, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo,
};
/// A trait used to power [list-like] operations via [reflection]. /// A trait used to power [list-like] operations via [reflection].
/// ///
@ -271,6 +276,11 @@ impl Reflect for DynamicList {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -352,6 +362,8 @@ impl Reflect for DynamicList {
} }
} }
impl_type_path!((in bevy_reflect) DynamicList);
impl Debug for DynamicList { impl Debug for DynamicList {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.debug(f) self.debug(f)

View File

@ -2,9 +2,12 @@ use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use bevy_reflect_derive::impl_type_path;
use bevy_utils::{Entry, HashMap}; use bevy_utils::{Entry, HashMap};
use crate::{Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; use crate::{
self as bevy_reflect, DynamicTypePath, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo,
};
/// A trait used to power [map-like] operations via [reflection]. /// A trait used to power [map-like] operations via [reflection].
/// ///
@ -307,6 +310,11 @@ impl Reflect for DynamicMap {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -375,6 +383,8 @@ impl Reflect for DynamicMap {
} }
} }
impl_type_path!((in bevy_reflect) DynamicMap);
impl Debug for DynamicMap { impl Debug for DynamicMap {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.debug(f) self.debug(f)

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
array_debug, enum_debug, list_debug, map_debug, serde::Serializable, struct_debug, tuple_debug, array_debug, enum_debug, list_debug, map_debug, serde::Serializable, struct_debug, tuple_debug,
tuple_struct_debug, Array, Enum, List, Map, Struct, Tuple, TupleStruct, TypeInfo, Typed, tuple_struct_debug, Array, DynamicTypePath, Enum, List, Map, Struct, Tuple, TupleStruct,
ValueInfo, TypeInfo, Typed, ValueInfo,
}; };
use std::{ use std::{
any::{self, Any, TypeId}, any::{self, Any, TypeId},
@ -93,6 +93,14 @@ pub trait Reflect: Any + Send + Sync {
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>; fn get_represented_type_info(&self) -> Option<&'static TypeInfo>;
/// Returns the [`TypePath`] implementation for the underlying type.
///
/// Methods on [`DynamicTypePath`] suffer the same performance concerns as [`get_represented_type_info`].
///
/// [`TypePath`]: crate::TypePath
/// [`get_represented_type_info`]: Reflect::get_represented_type_info
fn get_type_path(&self) -> &dyn DynamicTypePath;
/// Returns the value as a [`Box<dyn Any>`][std::any::Any]. /// Returns the value as a [`Box<dyn Any>`][std::any::Any].
fn into_any(self: Box<Self>) -> Box<dyn Any>; fn into_any(self: Box<Self>) -> Box<dyn Any>;

View File

@ -1,4 +1,8 @@
use crate::{NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; use crate::{
self as bevy_reflect, DynamicTypePath, NamedField, Reflect, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo,
};
use bevy_reflect_derive::impl_type_path;
use bevy_utils::{Entry, HashMap}; use bevy_utils::{Entry, HashMap};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::{ use std::{
@ -401,6 +405,11 @@ impl Reflect for DynamicStruct {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -485,6 +494,8 @@ impl Reflect for DynamicStruct {
} }
} }
impl_type_path!((in bevy_reflect) DynamicStruct);
impl Debug for DynamicStruct { impl Debug for DynamicStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.debug(f) self.debug(f)

View File

@ -1,5 +1,8 @@
use bevy_reflect_derive::impl_type_path;
use crate::{ use crate::{
FromReflect, GetTypeRegistration, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, self as bevy_reflect, utility::GenericTypePathCell, DynamicTypePath, FromReflect,
GetTypeRegistration, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath,
TypeRegistration, Typed, UnnamedField, TypeRegistration, Typed, UnnamedField,
}; };
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
@ -318,6 +321,11 @@ impl Reflect for DynamicTuple {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -393,6 +401,8 @@ impl Reflect for DynamicTuple {
} }
} }
impl_type_path!((in bevy_reflect) DynamicTuple);
/// Applies the elements of `b` to the corresponding elements of `a`. /// Applies the elements of `b` to the corresponding elements of `a`.
/// ///
/// # Panics /// # Panics
@ -467,7 +477,7 @@ pub fn tuple_debug(dyn_tuple: &dyn Tuple, f: &mut std::fmt::Formatter<'_>) -> st
macro_rules! impl_reflect_tuple { macro_rules! impl_reflect_tuple {
{$($index:tt : $name:tt),*} => { {$($index:tt : $name:tt),*} => {
impl<$($name: Reflect),*> Tuple for ($($name,)*) { impl<$($name: Reflect + TypePath),*> Tuple for ($($name,)*) {
#[inline] #[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> { fn field(&self, index: usize) -> Option<&dyn Reflect> {
match index { match index {
@ -519,7 +529,7 @@ macro_rules! impl_reflect_tuple {
} }
} }
impl<$($name: Reflect),*> Reflect for ($($name,)*) { impl<$($name: Reflect + TypePath),*> Reflect for ($($name,)*) {
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
} }
@ -528,6 +538,11 @@ macro_rules! impl_reflect_tuple {
Some(<Self as Typed>::type_info()) Some(<Self as Typed>::type_info())
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
@ -582,7 +597,7 @@ macro_rules! impl_reflect_tuple {
} }
} }
impl <$($name: Reflect),*> Typed for ($($name,)*) { impl <$($name: Reflect + TypePath),*> Typed for ($($name,)*) {
fn type_info() -> &'static TypeInfo { fn type_info() -> &'static TypeInfo {
static CELL: $crate::utility::GenericTypeInfoCell = $crate::utility::GenericTypeInfoCell::new(); static CELL: $crate::utility::GenericTypeInfoCell = $crate::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self, _>(|| { CELL.get_or_insert::<Self, _>(|| {
@ -595,13 +610,30 @@ macro_rules! impl_reflect_tuple {
} }
} }
impl<$($name: Reflect + Typed),*> GetTypeRegistration for ($($name,)*) { impl <$($name: Reflect + TypePath),*> TypePath for ($($name,)*) {
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() $(+ <$name as TypePath>::type_path())* + ")"
})
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
"(".to_owned() $(+ <$name as TypePath>::short_type_path())* + ")"
})
}
}
impl<$($name: Reflect + TypePath),*> GetTypeRegistration for ($($name,)*) {
fn get_type_registration() -> TypeRegistration { fn get_type_registration() -> TypeRegistration {
TypeRegistration::of::<($($name,)*)>() TypeRegistration::of::<($($name,)*)>()
} }
} }
impl<$($name: FromReflect),*> FromReflect for ($($name,)*) impl<$($name: FromReflect + TypePath),*> FromReflect for ($($name,)*)
{ {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> { fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() { if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() {

View File

@ -1,4 +1,9 @@
use crate::{Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, UnnamedField}; use bevy_reflect_derive::impl_type_path;
use crate::{
self as bevy_reflect, DynamicTypePath, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo,
UnnamedField,
};
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::slice::Iter; use std::slice::Iter;
@ -303,6 +308,11 @@ impl Reflect for DynamicTupleStruct {
self.represented_type self.represented_type
} }
#[inline]
fn get_type_path(&self) -> &dyn DynamicTypePath {
self
}
#[inline] #[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> { fn into_any(self: Box<Self>) -> Box<dyn Any> {
self self
@ -386,6 +396,8 @@ impl Reflect for DynamicTupleStruct {
} }
} }
impl_type_path!((in bevy_reflect) DynamicTupleStruct);
impl Debug for DynamicTupleStruct { impl Debug for DynamicTupleStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.debug(f) self.debug(f)

View File

@ -24,7 +24,7 @@ use std::fmt::Debug;
/// ///
/// ``` /// ```
/// # use std::any::Any; /// # use std::any::Any;
/// # use bevy_reflect::{NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, ValueInfo}; /// # use bevy_reflect::{DynamicTypePath, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, ValueInfo};
/// # use bevy_reflect::utility::NonGenericTypeInfoCell; /// # use bevy_reflect::utility::NonGenericTypeInfoCell;
/// use bevy_reflect::Typed; /// use bevy_reflect::Typed;
/// ///
@ -51,6 +51,7 @@ use std::fmt::Debug;
/// # impl Reflect for MyStruct { /// # impl Reflect for MyStruct {
/// # fn type_name(&self) -> &str { todo!() } /// # fn type_name(&self) -> &str { todo!() }
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() } /// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn get_type_path(&self) -> &dyn DynamicTypePath { todo!() }
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() } /// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() } /// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() } /// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }

View File

@ -0,0 +1,167 @@
/// A static accessor to type paths and names.
///
/// The engine uses this trait over [`std::any::type_name`] for stability and flexibility.
///
/// This trait is automatically implemented by the `#[derive(Reflect)]` macro
/// and allows type path information to be processed without an instance of that type.
///
/// Implementors may have difficulty in generating references with static
/// lifetimes. Luckily, this crate comes with some [utility] structs, to make generating these
/// statics much simpler.
///
/// # Stability
///
/// Certain parts of the engine, e.g. [(de)serialization], rely on type paths as identifiers
/// for matching dynamic values to concrete types.
///
/// Using [`std::any::type_name`], a scene containing `my_crate::foo::MyComponent` would break,
/// failing to deserialize if the component was moved from the `foo` module to the `bar` module,
/// becoming `my_crate::bar::MyComponent`.
/// This trait, through attributes when deriving itself or [`Reflect`], can ensure breaking changes are avoidable.
///
/// The only external factor we rely on for stability when deriving is the [`module_path!`] macro,
/// only if the derive does not provide a `#[type_path = "..."]` attribute.
///
/// # Anonymity
///
/// Some methods on this trait return `Option<&'static str>` over `&'static str`
/// because not all types define all parts of a type path, for example the array type `[T; N]`.
///
/// Such types are 'anonymous' in that they have only a defined [`type_path`] and [`short_type_path`]
/// and the methods [`crate_name`], [`module_path`] and [`type_ident`] all return `None`.
///
/// Primitives are treated like anonymous types, except they also have a defined [`type_ident`].
///
/// # Example
///
/// ```rust
/// use bevy_reflect::TypePath;
///
/// // This type path will not change with compiler versions or recompiles,
/// // although it will not be the same if the definition is moved.
/// #[derive(TypePath)]
/// struct NonStableTypePath;
///
/// // This type path will never change, even if the definition is moved.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo"]
/// struct StableTypePath;
///
/// // Type paths can have any number of path segments.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo::bar::baz"]
/// struct DeeplyNestedStableTypePath;
///
/// // Including just a crate name!
/// #[derive(TypePath)]
/// #[type_path = "my_crate"]
/// struct ShallowStableTypePath;
///
/// // We can also rename the identifier/name of types.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo"]
/// #[type_name = "RenamedStableTypePath"]
/// struct NamedStableTypePath;
///
/// // Generics are also supported.
/// #[derive(TypePath)]
/// #[type_path = "my_crate::foo"]
/// struct StableGenericTypePath<T, const N: usize>([T; N]);
/// ```
///
/// [utility]: crate::utility
/// [(de)serialization]: crate::serde::UntypedReflectDeserializer
/// [`Reflect`]: crate::Reflect
/// [`type_path`]: TypePath::type_path
/// [`short_type_path`]: TypePath::short_type_path
/// [`crate_name`]: TypePath::crate_name
/// [`module_path`]: TypePath::module_path
/// [`type_ident`]: TypePath::type_ident
pub trait TypePath: 'static {
/// Returns the fully qualified path of the underlying type.
///
/// Generic parameter types are also fully expanded.
///
/// For `Option<PhantomData>`, this is `"core::option::Option<core::marker::PhantomData>"`.
fn type_path() -> &'static str;
/// Returns a short, pretty-print enabled path to the type.
///
/// Generic parameter types are also shortened.
///
/// For `Option<PhantomData>`, this is `"Option<PhantomData>"`.
fn short_type_path() -> &'static str;
/// Returns the name of the type, or [`None`] if it is [anonymous].
///
/// Primitive types will return [`Some`].
///
/// For `Option<PhantomData>`, this is `"Option"`.
///
/// [anonymous]: TypePath#anonymity
fn type_ident() -> Option<&'static str> {
None
}
/// Returns the name of the crate the type is in, or [`None`] if it is [anonymous].
///
/// For `Option<PhantomData>`, this is `"core"`.
///
/// [anonymous]: TypePath#anonymity
fn crate_name() -> Option<&'static str> {
None
}
/// Returns the path to the moudle the type is in, or [`None`] if it is [anonymous].
///
/// For `Option<PhantomData>`, this is `"core::option"`.
///
/// [anonymous]: TypePath#anonymity
fn module_path() -> Option<&'static str> {
None
}
}
/// Dynamic dispatch for [`TypePath`].
///
/// Retrieved using [`Reflect::get_type_path`].
///
/// [`Reflect::get_type_path`]: crate::Reflect::get_type_path
pub trait DynamicTypePath {
/// See [`TypePath::type_path`].
fn reflect_type_path(&self) -> &str;
/// See [`TypePath::short_type_path`].
fn reflect_short_type_path(&self) -> &str;
/// See [`TypePath::type_ident`].
fn reflect_type_ident(&self) -> Option<&str>;
/// See [`TypePath::crate_name`].
fn reflect_crate_name(&self) -> Option<&str>;
/// See [`TypePath::module_path`].
fn reflect_module_path(&self) -> Option<&str>;
}
impl<T: TypePath> DynamicTypePath for T {
fn reflect_type_path(&self) -> &str {
Self::type_path()
}
fn reflect_short_type_path(&self) -> &str {
Self::short_type_path()
}
fn reflect_type_ident(&self) -> Option<&str> {
Self::type_ident()
}
fn reflect_crate_name(&self) -> Option<&str> {
Self::crate_name()
}
fn reflect_module_path(&self) -> Option<&str> {
Self::module_path()
}
}

View File

@ -9,132 +9,220 @@ use std::{
hash::BuildHasher, hash::BuildHasher,
}; };
/// A type that can be stored in a ([`Non`])[`GenericTypeCell`].
///
/// [`Non`]: NonGenericTypeCell
pub trait TypedProperty: sealed::Sealed {
type Stored: 'static;
}
/// Used to store a [`String`] in a [`GenericTypePathCell`] as part of a [`TypePath`] implementation.
///
/// [`TypePath`]: crate::TypePath
pub struct TypePathComponent;
mod sealed {
use super::{TypeInfo, TypePathComponent, TypedProperty};
pub trait Sealed {}
impl Sealed for TypeInfo {}
impl Sealed for TypePathComponent {}
impl TypedProperty for TypeInfo {
type Stored = Self;
}
impl TypedProperty for TypePathComponent {
type Stored = String;
}
}
/// A container for [`TypeInfo`] over non-generic types, allowing instances to be stored statically. /// A container for [`TypeInfo`] over non-generic types, allowing instances to be stored statically.
/// ///
/// This is specifically meant for use with _non_-generic types. If your type _is_ generic, /// This is specifically meant for use with _non_-generic types. If your type _is_ generic,
/// then use [`GenericTypeInfoCell`] instead. Otherwise, it will not take into account all /// then use [`GenericTypeCell`] instead. Otherwise, it will not take into account all
/// monomorphizations of your type. /// monomorphizations of your type.
/// ///
/// Non-generic [`TypePath`]s should be trivially generated with string literals and [`concat!`].
///
/// ## Example /// ## Example
/// ///
/// ``` /// ```
/// # use std::any::Any; /// # use std::any::Any;
/// # use bevy_reflect::{NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, Typed, TypeInfo}; /// # use bevy_reflect::{DynamicTypePath, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, Typed, TypeInfo};
/// use bevy_reflect::utility::NonGenericTypeInfoCell; /// use bevy_reflect::utility::NonGenericTypeInfoCell;
/// ///
/// struct Foo { /// struct Foo {
/// bar: i32 /// bar: i32
/// } /// }
/// ///
/// impl Typed for Foo { /// impl Typed for Foo {
/// fn type_info() -> &'static TypeInfo { /// fn type_info() -> &'static TypeInfo {
/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); /// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
/// CELL.get_or_set(|| { /// CELL.get_or_set(|| {
/// let fields = [NamedField::new::<i32>("bar")]; /// let fields = [NamedField::new::<i32>("bar")];
/// let info = StructInfo::new::<Self>("Foo", &fields); /// let info = StructInfo::new::<Self>("Foo", &fields);
/// TypeInfo::Struct(info) /// TypeInfo::Struct(info)
/// }) /// })
/// } /// }
/// } /// }
/// # /// #
/// # impl Reflect for Foo { /// # impl Reflect for Foo {
/// # fn type_name(&self) -> &str { todo!() } /// # fn type_name(&self) -> &str { todo!() }
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() } /// # fn get_type_path(&self) -> &dyn DynamicTypePath { todo!() }
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() } /// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() } /// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() } /// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() } /// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() } /// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() } /// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
/// # fn apply(&mut self, value: &dyn Reflect) { todo!() } /// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() } /// # fn apply(&mut self, value: &dyn Reflect) { todo!() }
/// # fn reflect_ref(&self) -> ReflectRef { todo!() } /// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() } /// # fn reflect_ref(&self) -> ReflectRef { todo!() }
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() } /// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() } /// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
/// # } /// # }
/// ``` /// ```
pub struct NonGenericTypeInfoCell(OnceBox<TypeInfo>); ///
/// [`TypePath`]: crate::TypePath
pub struct NonGenericTypeCell<T: TypedProperty>(OnceBox<T::Stored>);
impl NonGenericTypeInfoCell { /// See [`NonGenericTypeCell`].
/// Initialize a [`NonGenericTypeInfoCell`] for non-generic types. pub type NonGenericTypeInfoCell = NonGenericTypeCell<TypeInfo>;
impl<T: TypedProperty> NonGenericTypeCell<T> {
/// Initialize a [`NonGenericTypeCell`] for non-generic types.
pub const fn new() -> Self { pub const fn new() -> Self {
Self(OnceBox::new()) Self(OnceBox::new())
} }
/// Returns a reference to the [`TypeInfo`] stored in the cell. /// Returns a reference to the [`TypedProperty`] stored in the cell.
/// ///
/// If there is no [`TypeInfo`] found, a new one will be generated from the given function. /// If there is no entry found, a new one will be generated from the given function.
/// pub fn get_or_set<F>(&self, f: F) -> &T::Stored
/// [`TypeInfos`]: TypeInfo
pub fn get_or_set<F>(&self, f: F) -> &TypeInfo
where where
F: FnOnce() -> TypeInfo, F: FnOnce() -> T::Stored,
{ {
self.0.get_or_init(|| Box::new(f())) self.0.get_or_init(|| Box::new(f()))
} }
} }
/// A container for [`TypeInfo`] over generic types, allowing instances to be stored statically. /// A container for [`TypedProperty`] over generic types, allowing instances to be stored statically.
/// ///
/// This is specifically meant for use with generic types. If your type isn't generic, /// This is specifically meant for use with generic types. If your type isn't generic,
/// then use [`NonGenericTypeInfoCell`] instead as it should be much more performant. /// then use [`NonGenericTypeCell`] instead as it should be much more performant.
/// ///
/// ## Example /// `#[derive(TypePath)]` and [`impl_type_path`] should always be used over [`GenericTypePathCell`]
/// where possible.
///
/// ## Examples
///
/// Implementing [`TypeInfo`] with generics.
/// ///
/// ``` /// ```
/// # use std::any::Any; /// # use std::any::Any;
/// # use bevy_reflect::{Reflect, ReflectMut, ReflectOwned, ReflectRef, TupleStructInfo, Typed, TypeInfo, UnnamedField}; /// # use bevy_reflect::{DynamicTypePath, Reflect, ReflectMut, ReflectOwned, ReflectRef, TupleStructInfo, Typed, TypeInfo, UnnamedField};
/// use bevy_reflect::utility::GenericTypeInfoCell; /// use bevy_reflect::utility::GenericTypeInfoCell;
/// ///
/// struct Foo<T: Reflect>(T); /// struct Foo<T>(T);
/// ///
/// impl<T: Reflect> Typed for Foo<T> { /// impl<T: Reflect> Typed for Foo<T> {
/// fn type_info() -> &'static TypeInfo { /// fn type_info() -> &'static TypeInfo {
/// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); /// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
/// CELL.get_or_insert::<Self, _>(|| { /// CELL.get_or_insert::<Self, _>(|| {
/// let fields = [UnnamedField::new::<T>(0)]; /// let fields = [UnnamedField::new::<T>(0)];
/// let info = TupleStructInfo::new::<Self>("Foo", &fields); /// let info = TupleStructInfo::new::<Self>("Foo", &fields);
/// TypeInfo::TupleStruct(info) /// TypeInfo::TupleStruct(info)
/// }) /// })
/// } /// }
/// } /// }
/// # /// #
/// # impl<T: Reflect> Reflect for Foo<T> { /// # impl<T: Reflect> Reflect for Foo<T> {
/// # fn type_name(&self) -> &str { todo!() } /// # fn type_name(&self) -> &str { todo!() }
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() } /// # fn get_type_path(&self) -> &dyn DynamicTypePath { todo!() }
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() } /// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() } /// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() } /// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() } /// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() } /// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() } /// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
/// # fn apply(&mut self, value: &dyn Reflect) { todo!() } /// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() } /// # fn apply(&mut self, value: &dyn Reflect) { todo!() }
/// # fn reflect_ref(&self) -> ReflectRef { todo!() } /// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() } /// # fn reflect_ref(&self) -> ReflectRef { todo!() }
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() } /// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() } /// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
/// # } /// # }
/// ``` /// ```
pub struct GenericTypeInfoCell(OnceBox<RwLock<HashMap<TypeId, &'static TypeInfo>>>); ///
/// Implementing [`TypePath`] with generics.
///
/// ```
/// # use std::any::Any;
/// # use bevy_reflect::{DynamicTypePath, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath};
/// use bevy_reflect::utility::GenericTypePathCell;
///
/// struct Foo<T>(T);
///
/// impl<T: Reflect + TypePath> TypePath for Foo<T> {
/// fn type_path() -> &'static str {
/// static CELL: GenericTypePathCell = GenericTypePathCell::new();
/// CELL.get_or_insert::<Self, _>(|| format!("my_crate::foo::Foo<{}>", T::type_path()))
/// }
///
/// fn short_type_path() -> &'static str {
/// static CELL: GenericTypePathCell = GenericTypePathCell::new();
/// CELL.get_or_insert::<Self, _>(|| format!("Foo<{}>", T::short_type_path()))
/// }
/// }
/// #
/// # impl<T: Reflect> Reflect for Foo<T> {
/// # fn type_name(&self) -> &str { todo!() }
/// # fn get_type_path(&self) -> &dyn DynamicTypePath { todo!() }
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_any(self: Box<Self>) -> Box<dyn Any> { todo!() }
/// # fn as_any(&self) -> &dyn Any { todo!() }
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
/// # fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> { todo!() }
/// # fn as_reflect(&self) -> &dyn Reflect { todo!() }
/// # fn as_reflect_mut(&mut self) -> &mut dyn Reflect { todo!() }
/// # fn apply(&mut self, value: &dyn Reflect) { todo!() }
/// # fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # fn reflect_ref(&self) -> ReflectRef { todo!() }
/// # fn reflect_mut(&mut self) -> ReflectMut { todo!() }
/// # fn reflect_owned(self: Box<Self>) -> ReflectOwned { todo!() }
/// # fn clone_value(&self) -> Box<dyn Reflect> { todo!() }
/// # }
/// ```
/// [`impl_type_path`]: crate::impl_type_path
/// [`TypePath`]: crate::TypePath
pub struct GenericTypeCell<T: TypedProperty>(OnceBox<RwLock<HashMap<TypeId, &'static T::Stored>>>);
impl GenericTypeInfoCell { /// See [`GenericTypeCell`].
/// Initialize a [`GenericTypeInfoCell`] for generic types. pub type GenericTypeInfoCell = GenericTypeCell<TypeInfo>;
/// See [`GenericTypeCell`].
pub type GenericTypePathCell = GenericTypeCell<TypePathComponent>;
impl<T: TypedProperty> GenericTypeCell<T> {
/// Initialize a [`GenericTypeCell`] for generic types.
pub const fn new() -> Self { pub const fn new() -> Self {
Self(OnceBox::new()) Self(OnceBox::new())
} }
/// Returns a reference to the [`TypeInfo`] stored in the cell. /// Returns a reference to the [`TypedProperty`] stored in the cell.
/// ///
/// This method will then return the correct [`TypeInfo`] reference for the given type `T`. /// This method will then return the correct [`TypedProperty`] reference for the given type `T`.
/// If there is no [`TypeInfo`] found, a new one will be generated from the given function. /// If there is no entry found, a new one will be generated from the given function.
pub fn get_or_insert<T, F>(&self, f: F) -> &TypeInfo pub fn get_or_insert<G, F>(&self, f: F) -> &T::Stored
where where
T: Any + ?Sized, G: Any + ?Sized,
F: FnOnce() -> TypeInfo, F: FnOnce() -> T::Stored,
{ {
let type_id = TypeId::of::<T>(); let type_id = TypeId::of::<G>();
// let mapping = self.0.get_or_init(|| Box::new(RwLock::default())); // let mapping = self.0.get_or_init(|| Box::new(RwLock::default()));
let mapping = self.0.get_or_init(Box::default); let mapping = self.0.get_or_init(Box::default);
if let Some(info) = mapping.read().get(&type_id) { if let Some(info) = mapping.read().get(&type_id) {

View File

@ -1,4 +1,4 @@
use bevy_reflect::Reflect; use bevy_reflect::{Reflect, TypePath};
#[derive(Reflect)] #[derive(Reflect)]
struct Foo<T> { struct Foo<T> {
@ -6,10 +6,11 @@ struct Foo<T> {
} }
// Type that doesn't implement Reflect // Type that doesn't implement Reflect
#[derive(TypePath)]
struct NoReflect(f32); struct NoReflect(f32);
fn main() { fn main() {
let mut foo: Box<dyn Reflect> = Box::new(Foo::<NoReflect> { a: NoReflect(42.0) }); let mut foo: Box<dyn Reflect> = Box::new(Foo::<NoReflect> { a: NoReflect(42.0) });
// foo doesn't implement Reflect because NoReflect doesn't implement Reflect // foo doesn't implement Reflect because NoReflect doesn't implement Reflect
foo.get_field::<NoReflect>("a").unwrap(); foo.get_field::<NoReflect>("a").unwrap();
} }

View File

@ -1,13 +1,13 @@
error[E0599]: no method named `get_field` found for struct `Box<(dyn Reflect + 'static)>` in the current scope error[E0599]: no method named `get_field` found for struct `Box<(dyn Reflect + 'static)>` in the current scope
--> tests/reflect_derive/generics.fail.rs:14:9 --> tests/reflect_derive/generics.fail.rs:15:9
| |
14 | foo.get_field::<NoReflect>("a").unwrap(); 15 | foo.get_field::<NoReflect>("a").unwrap();
| ^^^^^^^^^ method not found in `Box<dyn Reflect>` | ^^^^^^^^^ method not found in `Box<dyn Reflect>`
error[E0277]: the trait bound `NoReflect: Reflect` is not satisfied error[E0277]: the trait bound `NoReflect: Reflect` is not satisfied
--> tests/reflect_derive/generics.fail.rs:12:37 --> tests/reflect_derive/generics.fail.rs:13:37
| |
12 | let mut foo: Box<dyn Reflect> = Box::new(Foo::<NoReflect> { a: NoReflect(42.0) }); 13 | let mut foo: Box<dyn Reflect> = Box::new(Foo::<NoReflect> { a: NoReflect(42.0) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Reflect` is not implemented for `NoReflect` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Reflect` is not implemented for `NoReflect`
| |
= help: the following other types implement trait `Reflect`: = help: the following other types implement trait `Reflect`:

View File

@ -12,7 +12,7 @@ use bevy_core::cast_slice;
use bevy_derive::EnumVariantMeta; use bevy_derive::EnumVariantMeta;
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem}; use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
use bevy_math::*; use bevy_math::*;
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_utils::{tracing::error, Hashed}; use bevy_utils::{tracing::error, Hashed};
use std::{collections::BTreeMap, hash::Hash, iter::FusedIterator}; use std::{collections::BTreeMap, hash::Hash, iter::FusedIterator};
use thiserror::Error; use thiserror::Error;
@ -25,7 +25,7 @@ pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10; pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
// TODO: allow values to be unloaded after been submitting to the GPU to conserve memory // TODO: allow values to be unloaded after been submitting to the GPU to conserve memory
#[derive(Debug, TypeUuid, Clone)] #[derive(Debug, TypeUuid, TypePath, Clone)]
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"] #[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
pub struct Mesh { pub struct Mesh {
primitive_topology: PrimitiveTopology, primitive_topology: PrimitiveTopology,

View File

@ -6,7 +6,7 @@ use bevy_ecs::{
reflect::ReflectMapEntities, reflect::ReflectMapEntities,
}; };
use bevy_math::Mat4; use bevy_math::Mat4;
use bevy_reflect::{Reflect, TypeUuid}; use bevy_reflect::{Reflect, TypePath, TypeUuid};
use std::ops::Deref; use std::ops::Deref;
#[derive(Component, Debug, Default, Clone, Reflect)] #[derive(Component, Debug, Default, Clone, Reflect)]
@ -24,7 +24,7 @@ impl MapEntities for SkinnedMesh {
} }
} }
#[derive(Debug, TypeUuid)] #[derive(Debug, TypeUuid, TypePath)]
#[uuid = "b9f155a9-54ec-4026-988f-e0a03e99a76f"] #[uuid = "b9f155a9-54ec-4026-988f-e0a03e99a76f"]
pub struct SkinnedMeshInverseBindposes(Box<[Mat4]>); pub struct SkinnedMeshInverseBindposes(Box<[Mat4]>);

View File

@ -1,7 +1,7 @@
use super::ShaderDefVal; use super::ShaderDefVal;
use crate::define_atomic_id; use crate::define_atomic_id;
use bevy_asset::{AssetLoader, AssetPath, Handle, LoadContext, LoadedAsset}; use bevy_asset::{AssetLoader, AssetPath, Handle, LoadContext, LoadedAsset};
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_utils::{tracing::error, BoxedFuture, HashMap}; use bevy_utils::{tracing::error, BoxedFuture, HashMap};
#[cfg(feature = "shader_format_glsl")] #[cfg(feature = "shader_format_glsl")]
use naga::back::wgsl::WriterFlags; use naga::back::wgsl::WriterFlags;
@ -31,7 +31,7 @@ pub enum ShaderReflectError {
} }
/// A shader, as defined by its [`ShaderSource`] and [`ShaderStage`](naga::ShaderStage) /// A shader, as defined by its [`ShaderSource`] and [`ShaderStage`](naga::ShaderStage)
/// This is an "unprocessed" shader. It can contain preprocessor directives. /// This is an "unprocessed" shader. It can contain preprocessor directives.
#[derive(Debug, Clone, TypeUuid)] #[derive(Debug, Clone, TypeUuid, TypePath)]
#[uuid = "d95bc916-6c55-4de3-9622-37e7b6969fda"] #[uuid = "d95bc916-6c55-4de3-9622-37e7b6969fda"]
pub struct Shader { pub struct Shader {
source: Source, source: Source,

View File

@ -69,7 +69,7 @@ bitflags::bitflags! {
const VISIBLE_IN_HIERARCHY = 1 << 1; const VISIBLE_IN_HIERARCHY = 1 << 1;
} }
} }
bevy_reflect::impl_reflect_value!(ComputedVisibilityFlags); bevy_reflect::impl_reflect_value!((in bevy_render::view) ComputedVisibilityFlags);
bevy_reflect::impl_from_reflect_value!(ComputedVisibilityFlags); bevy_reflect::impl_from_reflect_value!(ComputedVisibilityFlags);
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering

View File

@ -8,7 +8,7 @@ use bevy_ecs::{
reflect::{ReflectComponent, ReflectMapEntities}, reflect::{ReflectComponent, ReflectMapEntities},
world::World, world::World,
}; };
use bevy_reflect::{Reflect, TypeRegistryArc, TypeUuid}; use bevy_reflect::{Reflect, TypePath, TypeRegistryArc, TypeUuid};
use bevy_utils::HashMap; use bevy_utils::HashMap;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
@ -26,7 +26,7 @@ use serde::Serialize;
/// * adding the [`Handle<DynamicScene>`](bevy_asset::Handle) to an entity (the scene will only be /// * adding the [`Handle<DynamicScene>`](bevy_asset::Handle) to an entity (the scene will only be
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and /// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components) /// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
#[derive(Default, TypeUuid)] #[derive(Default, TypeUuid, TypePath)]
#[uuid = "749479b1-fb8c-4ff8-a775-623aa76014f5"] #[uuid = "749479b1-fb8c-4ff8-a775-623aa76014f5"]
pub struct DynamicScene { pub struct DynamicScene {
pub resources: Vec<Box<dyn Reflect>>, pub resources: Vec<Box<dyn Reflect>>,

View File

@ -4,7 +4,7 @@ use bevy_ecs::{
reflect::{ReflectComponent, ReflectMapEntities, ReflectResource}, reflect::{ReflectComponent, ReflectMapEntities, ReflectResource},
world::World, world::World,
}; };
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use crate::{DynamicScene, InstanceInfo, SceneSpawnError}; use crate::{DynamicScene, InstanceInfo, SceneSpawnError};
@ -14,7 +14,7 @@ use crate::{DynamicScene, InstanceInfo, SceneSpawnError};
/// * adding the [`Handle<Scene>`](bevy_asset::Handle) to an entity (the scene will only be /// * adding the [`Handle<Scene>`](bevy_asset::Handle) to an entity (the scene will only be
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and /// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components) /// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
#[derive(Debug, TypeUuid)] #[derive(Debug, TypeUuid, TypePath)]
#[uuid = "c156503c-edd9-4ec7-8d33-dab392df03cd"] #[uuid = "c156503c-edd9-4ec7-8d33-dab392df03cd"]
pub struct Scene { pub struct Scene {
pub world: World, pub world: World,

View File

@ -14,7 +14,7 @@ use bevy_ecs::{
}, },
}; };
use bevy_log::error; use bevy_log::error;
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_render::{ use bevy_render::{
extract_component::ExtractComponentPlugin, extract_component::ExtractComponentPlugin,
mesh::{Mesh, MeshVertexBufferLayout}, mesh::{Mesh, MeshVertexBufferLayout},
@ -60,11 +60,11 @@ use crate::{
/// ``` /// ```
/// # use bevy_sprite::{Material2d, MaterialMesh2dBundle}; /// # use bevy_sprite::{Material2d, MaterialMesh2dBundle};
/// # use bevy_ecs::prelude::*; /// # use bevy_ecs::prelude::*;
/// # use bevy_reflect::TypeUuid; /// # use bevy_reflect::{TypeUuid, TypePath};
/// # use bevy_render::{render_resource::{AsBindGroup, ShaderRef}, texture::Image, color::Color}; /// # use bevy_render::{render_resource::{AsBindGroup, ShaderRef}, texture::Image, color::Color};
/// # use bevy_asset::{Handle, AssetServer, Assets}; /// # use bevy_asset::{Handle, AssetServer, Assets};
/// ///
/// #[derive(AsBindGroup, TypeUuid, Debug, Clone)] /// #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
/// #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] /// #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
/// pub struct CustomMaterial { /// pub struct CustomMaterial {
/// // Uniform bindings must implement `ShaderType`, which will be used to convert the value to /// // Uniform bindings must implement `ShaderType`, which will be used to convert the value to
@ -111,7 +111,7 @@ use crate::{
/// @group(1) @binding(2) /// @group(1) @binding(2)
/// var color_sampler: sampler; /// var color_sampler: sampler;
/// ``` /// ```
pub trait Material2d: AsBindGroup + Send + Sync + Clone + TypeUuid + Sized + 'static { pub trait Material2d: AsBindGroup + Send + Sync + Clone + TypeUuid + TypePath + Sized {
/// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader /// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader
/// will be used. /// will be used.
fn vertex_shader() -> ShaderRef { fn vertex_shader() -> ShaderRef {

View File

@ -1,11 +1,11 @@
use ab_glyph::{FontArc, FontVec, InvalidFont, OutlinedGlyph}; use ab_glyph::{FontArc, FontVec, InvalidFont, OutlinedGlyph};
use bevy_reflect::TypeUuid; use bevy_reflect::{TypePath, TypeUuid};
use bevy_render::{ use bevy_render::{
render_resource::{Extent3d, TextureDimension, TextureFormat}, render_resource::{Extent3d, TextureDimension, TextureFormat},
texture::Image, texture::Image,
}; };
#[derive(Debug, TypeUuid, Clone)] #[derive(Debug, TypeUuid, TypePath, Clone)]
#[uuid = "97059ac6-c9ba-4da9-95b6-bed82c3ce198"] #[uuid = "97059ac6-c9ba-4da9-95b6-bed82c3ce198"]
pub struct Font { pub struct Font {
pub font: FontArc, pub font: FontArc,

View File

@ -2,6 +2,7 @@ use crate::{error::TextError, Font, FontAtlas};
use ab_glyph::{GlyphId, OutlinedGlyph, Point}; use ab_glyph::{GlyphId, OutlinedGlyph, Point};
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_math::Vec2; use bevy_math::Vec2;
use bevy_reflect::TypePath;
use bevy_reflect::TypeUuid; use bevy_reflect::TypeUuid;
use bevy_render::texture::Image; use bevy_render::texture::Image;
use bevy_sprite::TextureAtlas; use bevy_sprite::TextureAtlas;
@ -10,7 +11,7 @@ use bevy_utils::HashMap;
type FontSizeKey = FloatOrd; type FontSizeKey = FloatOrd;
#[derive(TypeUuid)] #[derive(TypeUuid, TypePath)]
#[uuid = "73ba778b-b6b5-4f45-982d-d21b6b86ace2"] #[uuid = "73ba778b-b6b5-4f45-982d-d21b6b86ace2"]
pub struct FontAtlasSet { pub struct FontAtlasSet {
font_atlases: HashMap<FontSizeKey, Vec<FontAtlas>>, font_atlases: HashMap<FontSizeKey, Vec<FontAtlas>>,

View File

@ -2,7 +2,7 @@
use bevy::gltf::GltfPlugin; use bevy::gltf::GltfPlugin;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::reflect::TypeUuid; use bevy::reflect::{TypePath, TypeUuid};
use bevy::render::mesh::{MeshVertexAttribute, MeshVertexBufferLayout}; use bevy::render::mesh::{MeshVertexAttribute, MeshVertexBufferLayout};
use bevy::render::render_resource::*; use bevy::render::render_resource::*;
use bevy::sprite::{ use bevy::sprite::{
@ -55,7 +55,7 @@ fn setup(
/// This custom material uses barycentric coordinates from /// This custom material uses barycentric coordinates from
/// `ATTRIBUTE_BARYCENTRIC` to shade a white border around each triangle. The /// `ATTRIBUTE_BARYCENTRIC` to shade a white border around each triangle. The
/// thickness of the border is animated using the global time shader uniform. /// thickness of the border is animated using the global time shader uniform.
#[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "50ffce9e-1582-42e9-87cb-2233724426c0"] #[uuid = "50ffce9e-1582-42e9-87cb-2233724426c0"]
struct CustomMaterial {} struct CustomMaterial {}

View File

@ -3,7 +3,7 @@
use bevy::{ use bevy::{
pbr::{MaterialPipeline, MaterialPipelineKey}, pbr::{MaterialPipeline, MaterialPipelineKey},
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::{ render::{
mesh::{MeshVertexBufferLayout, PrimitiveTopology}, mesh::{MeshVertexBufferLayout, PrimitiveTopology},
render_resource::{ render_resource::{
@ -62,7 +62,7 @@ fn setup(
}); });
} }
#[derive(Default, AsBindGroup, TypeUuid, Debug, Clone)] #[derive(Default, AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "050ce6ac-080a-4d8c-b6b5-b5bab7560d8f"] #[uuid = "050ce6ac-080a-4d8c-b6b5-b5bab7560d8f"]
struct LineMaterial { struct LineMaterial {
#[uniform(0)] #[uniform(0)]

View File

@ -5,7 +5,7 @@ use bevy::{
math::vec2, math::vec2,
pbr::CascadeShadowConfigBuilder, pbr::CascadeShadowConfigBuilder,
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::{ render::{
render_resource::{ render_resource::{
AsBindGroup, Extent3d, SamplerDescriptor, ShaderRef, TextureDimension, TextureFormat, AsBindGroup, Extent3d, SamplerDescriptor, ShaderRef, TextureDimension, TextureFormat,
@ -689,7 +689,7 @@ impl Material for ColorGradientMaterial {
} }
} }
#[derive(AsBindGroup, Debug, Clone, TypeUuid)] #[derive(AsBindGroup, Debug, Clone, TypeUuid, TypePath)]
#[uuid = "117f64fe-6844-1822-8926-e3ed372291c8"] #[uuid = "117f64fe-6844-1822-8926-e3ed372291c8"]
pub struct ColorGradientMaterial {} pub struct ColorGradientMaterial {}

View File

@ -3,12 +3,12 @@
use bevy::{ use bevy::{
asset::{AssetLoader, LoadContext, LoadedAsset}, asset::{AssetLoader, LoadContext, LoadedAsset},
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
utils::BoxedFuture, utils::BoxedFuture,
}; };
use serde::Deserialize; use serde::Deserialize;
#[derive(Debug, Deserialize, TypeUuid)] #[derive(Debug, Deserialize, TypeUuid, TypePath)]
#[uuid = "39cadc56-aa9c-4543-8640-a018b74b5052"] #[uuid = "39cadc56-aa9c-4543-8640-a018b74b5052"]
pub struct CustomAsset { pub struct CustomAsset {
pub value: i32, pub value: i32,

View File

@ -3,14 +3,14 @@ use bevy::audio::AddAudioSource;
use bevy::audio::AudioPlugin; use bevy::audio::AudioPlugin;
use bevy::audio::Source; use bevy::audio::Source;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::reflect::TypeUuid; use bevy::reflect::{TypePath, TypeUuid};
use bevy::utils::Duration; use bevy::utils::Duration;
// This struct usually contains the data for the audio being played. // This struct usually contains the data for the audio being played.
// This is where data read from an audio file would be stored, for example. // This is where data read from an audio file would be stored, for example.
// Implementing `TypeUuid` will automatically implement `Asset`. // Implementing `TypeUuid` will automatically implement `Asset`.
// This allows the type to be registered as an asset. // This allows the type to be registered as an asset.
#[derive(TypeUuid)] #[derive(TypePath, TypeUuid)]
#[uuid = "c2090c23-78fd-44f1-8508-c89b1f3cec29"] #[uuid = "c2090c23-78fd-44f1-8508-c89b1f3cec29"]
struct SineAudio { struct SineAudio {
frequency: f32, frequency: f32,

View File

@ -1,7 +1,11 @@
//! A shader that uses dynamic data like the time since startup. //! A shader that uses dynamic data like the time since startup.
//! The time data is in the globals binding which is part of the `mesh_view_bindings` shader import. //! The time data is in the globals binding which is part of the `mesh_view_bindings` shader import.
use bevy::{prelude::*, reflect::TypeUuid, render::render_resource::*}; use bevy::{
prelude::*,
reflect::{TypePath, TypeUuid},
render::render_resource::*,
};
fn main() { fn main() {
App::new() App::new()
@ -31,7 +35,7 @@ fn setup(
}); });
} }
#[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "a3d71c04-d054-4946-80f8-ba6cfbc90cad"] #[uuid = "a3d71c04-d054-4946-80f8-ba6cfbc90cad"]
struct CustomMaterial {} struct CustomMaterial {}

View File

@ -1,7 +1,7 @@
use bevy::{ use bevy::{
asset::LoadState, asset::LoadState,
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef}, render::render_resource::{AsBindGroup, ShaderRef},
}; };
@ -89,7 +89,7 @@ fn create_array_texture(
} }
} }
#[derive(AsBindGroup, Debug, Clone, TypeUuid)] #[derive(AsBindGroup, Debug, Clone, TypeUuid, TypePath)]
#[uuid = "9c5a0ddf-1eaf-41b4-9832-ed736fd26af3"] #[uuid = "9c5a0ddf-1eaf-41b4-9832-ed736fd26af3"]
struct ArrayTextureMaterial { struct ArrayTextureMaterial {
#[texture(0, dimension = "2d_array")] #[texture(0, dimension = "2d_array")]

View File

@ -3,7 +3,7 @@
use bevy::{ use bevy::{
pbr::{MaterialPipeline, MaterialPipelineKey}, pbr::{MaterialPipeline, MaterialPipelineKey},
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::{ render::{
mesh::{MeshVertexAttribute, MeshVertexBufferLayout}, mesh::{MeshVertexAttribute, MeshVertexBufferLayout},
render_resource::{ render_resource::{
@ -57,7 +57,7 @@ fn setup(
} }
// This is the struct that will be passed to your shader // This is the struct that will be passed to your shader
#[derive(AsBindGroup, Debug, Clone, TypeUuid)] #[derive(AsBindGroup, Debug, Clone, TypeUuid, TypePath)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CustomMaterial { pub struct CustomMaterial {
#[uniform(0)] #[uniform(0)]

View File

@ -3,7 +3,7 @@
use bevy::{ use bevy::{
pbr::{MaterialPipeline, MaterialPipelineKey}, pbr::{MaterialPipeline, MaterialPipelineKey},
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::{ render::{
mesh::MeshVertexBufferLayout, mesh::MeshVertexBufferLayout,
render_resource::{ render_resource::{
@ -75,7 +75,7 @@ impl Material for CustomMaterial {
} }
// This is the struct that will be passed to your shader // This is the struct that will be passed to your shader
#[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
#[bind_group_data(CustomMaterialKey)] #[bind_group_data(CustomMaterialKey)]
pub struct CustomMaterial { pub struct CustomMaterial {

View File

@ -2,7 +2,7 @@
use bevy::{ use bevy::{
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef}, render::render_resource::{AsBindGroup, ShaderRef},
}; };
@ -53,7 +53,7 @@ impl Material for CustomMaterial {
} }
// This is the struct that will be passed to your shader // This is the struct that will be passed to your shader
#[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CustomMaterial { pub struct CustomMaterial {
#[uniform(0)] #[uniform(0)]

View File

@ -3,7 +3,7 @@
use bevy::{ use bevy::{
pbr::{MaterialPipeline, MaterialPipelineKey}, pbr::{MaterialPipeline, MaterialPipelineKey},
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::{ render::{
mesh::MeshVertexBufferLayout, mesh::MeshVertexBufferLayout,
render_resource::{ render_resource::{
@ -47,7 +47,7 @@ fn setup(
} }
// This is the struct that will be passed to your shader // This is the struct that will be passed to your shader
#[derive(AsBindGroup, Clone, TypeUuid)] #[derive(AsBindGroup, Clone, TypeUuid, TypePath)]
#[uuid = "4ee9c363-1124-4113-890e-199d81b00281"] #[uuid = "4ee9c363-1124-4113-890e-199d81b00281"]
pub struct CustomMaterial { pub struct CustomMaterial {
#[uniform(0)] #[uniform(0)]

View File

@ -2,7 +2,7 @@
use bevy::{ use bevy::{
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef}, render::render_resource::{AsBindGroup, ShaderRef},
}; };
@ -66,7 +66,7 @@ fn rotate_camera(mut camera: Query<&mut Transform, With<MainCamera>>, time: Res<
cam_transform.look_at(Vec3::ZERO, Vec3::Y); cam_transform.look_at(Vec3::ZERO, Vec3::Y);
} }
#[derive(AsBindGroup, Debug, Clone, TypeUuid)] #[derive(AsBindGroup, Debug, Clone, TypeUuid, TypePath)]
#[uuid = "b62bb455-a72c-4b56-87bb-81e0554e234f"] #[uuid = "b62bb455-a72c-4b56-87bb-81e0554e234f"]
pub struct CustomMaterial { pub struct CustomMaterial {
#[texture(0)] #[texture(0)]

View File

@ -6,7 +6,7 @@ use bevy::{
core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass, NormalPrepass}, core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass, NormalPrepass},
pbr::{NotShadowCaster, PbrPlugin}, pbr::{NotShadowCaster, PbrPlugin},
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef, ShaderType}, render::render_resource::{AsBindGroup, ShaderRef, ShaderType},
}; };
@ -155,7 +155,7 @@ fn setup(
} }
// This is the struct that will be passed to your shader // This is the struct that will be passed to your shader
#[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[derive(AsBindGroup, TypePath, TypeUuid, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CustomMaterial { pub struct CustomMaterial {
#[uniform(0)] #[uniform(0)]
@ -204,7 +204,7 @@ struct ShowPrepassSettings {
} }
// This shader simply loads the prepass texture and outputs it directly // This shader simply loads the prepass texture and outputs it directly
#[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[derive(AsBindGroup, TypePath, TypeUuid, Debug, Clone)]
#[uuid = "0af99895-b96e-4451-bc12-c6b1c1c52750"] #[uuid = "0af99895-b96e-4451-bc12-c6b1c1c52750"]
pub struct PrepassOutputMaterial { pub struct PrepassOutputMaterial {
#[uniform(0)] #[uniform(0)]

View File

@ -3,7 +3,7 @@
use bevy::{ use bevy::{
prelude::*, prelude::*,
reflect::TypeUuid, reflect::{TypePath, TypeUuid},
render::{ render::{
render_asset::RenderAssets, render_asset::RenderAssets,
render_resource::{AsBindGroupError, PreparedBindGroup, *}, render_resource::{AsBindGroupError, PreparedBindGroup, *},
@ -85,7 +85,7 @@ fn setup(
}); });
} }
#[derive(Debug, Clone, TypeUuid)] #[derive(Debug, Clone, TypePath, TypeUuid)]
#[uuid = "8dd2b424-45a2-4a53-ac29-7ce356b2d5fe"] #[uuid = "8dd2b424-45a2-4a53-ac29-7ce356b2d5fe"]
struct BindlessMaterial { struct BindlessMaterial {
textures: Vec<Handle<Image>>, textures: Vec<Handle<Image>>,