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:
parent
94dce091a9
commit
1efc762924
@ -98,7 +98,7 @@ pub struct AssetServerInternal {
|
||||
/// use bevy_asset::{AssetServer, Handle};
|
||||
/// 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"]
|
||||
/// # struct Image;
|
||||
///
|
||||
@ -647,10 +647,10 @@ mod test {
|
||||
use crate::{loader::LoadedAsset, update_asset_storage_system};
|
||||
use bevy_app::{App, Update};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_utils::BoxedFuture;
|
||||
|
||||
#[derive(Debug, TypeUuid)]
|
||||
#[derive(Debug, TypeUuid, TypePath)]
|
||||
#[uuid = "a5189b72-0572-4290-a2e0-96f73a491c44"]
|
||||
struct PngAsset;
|
||||
|
||||
|
||||
@ -488,7 +488,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn asset_overwriting() {
|
||||
#[derive(bevy_reflect::TypeUuid)]
|
||||
#[derive(bevy_reflect::TypeUuid, bevy_reflect::TypePath)]
|
||||
#[uuid = "44115972-f31b-46e5-be5c-2b9aece6a52f"]
|
||||
struct MyAsset;
|
||||
let mut app = App::new();
|
||||
|
||||
@ -5,6 +5,7 @@ use crate::{
|
||||
use anyhow::Error;
|
||||
use anyhow::Result;
|
||||
use bevy_ecs::system::{Res, ResMut};
|
||||
use bevy_reflect::TypePath;
|
||||
use bevy_reflect::{TypeUuid, TypeUuidDynamic};
|
||||
use bevy_utils::{BoxedFuture, HashMap};
|
||||
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
|
||||
/// 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.
|
||||
pub trait AssetDynamic: Downcast + TypeUuidDynamic + Send + Sync + 'static {}
|
||||
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 {}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use anyhow::Result;
|
||||
use bevy_asset::{Asset, AssetLoader, LoadContext, LoadedAsset};
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_utils::BoxedFuture;
|
||||
use std::{io::Cursor, sync::Arc};
|
||||
|
||||
/// A source of audio data
|
||||
#[derive(Debug, Clone, TypeUuid)]
|
||||
#[derive(Debug, Clone, TypeUuid, TypePath)]
|
||||
#[uuid = "7a14806a-672b-443b-8d16-4f18afefa463"]
|
||||
pub struct AudioSource {
|
||||
/// Raw data of the audio source.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use bevy_math::Vec3;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_transform::prelude::Transform;
|
||||
use rodio::{Sink, SpatialSink};
|
||||
|
||||
@ -87,7 +87,7 @@ pub trait AudioSinkPlayback {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
#[derive(TypeUuid)]
|
||||
#[derive(TypePath, TypeUuid)]
|
||||
#[uuid = "8BEE570C-57C2-4FC0-8CFB-983A22F7D981"]
|
||||
pub struct AudioSink {
|
||||
// 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"]
|
||||
pub struct SpatialAudioSink {
|
||||
// This field is an Option in order to allow us to have a safe drop that will detach the sink.
|
||||
|
||||
@ -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);
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@ -12,7 +12,7 @@ use bevy_app::prelude::*;
|
||||
use bevy_asset::{AddAsset, Handle};
|
||||
use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
|
||||
use bevy_pbr::StandardMaterial;
|
||||
use bevy_reflect::{Reflect, TypeUuid};
|
||||
use bevy_reflect::{Reflect, TypePath, TypeUuid};
|
||||
use bevy_render::{
|
||||
mesh::{Mesh, MeshVertexAttribute},
|
||||
renderer::RenderDevice,
|
||||
@ -58,7 +58,7 @@ impl Plugin for GltfPlugin {
|
||||
}
|
||||
|
||||
/// Representation of a loaded glTF file.
|
||||
#[derive(Debug, TypeUuid)]
|
||||
#[derive(Debug, TypeUuid, TypePath)]
|
||||
#[uuid = "5c7d5f8a-f7b0-4e45-a09e-406c0372fea2"]
|
||||
pub struct Gltf {
|
||||
pub scenes: Vec<Handle<Scene>>,
|
||||
@ -78,7 +78,7 @@ pub struct Gltf {
|
||||
|
||||
/// A glTF node with all of its child nodes, its [`GltfMesh`],
|
||||
/// [`Transform`](bevy_transform::prelude::Transform) and an optional [`GltfExtras`].
|
||||
#[derive(Debug, Clone, TypeUuid)]
|
||||
#[derive(Debug, Clone, TypeUuid, TypePath)]
|
||||
#[uuid = "dad74750-1fd6-460f-ac51-0a7937563865"]
|
||||
pub struct GltfNode {
|
||||
pub children: Vec<GltfNode>,
|
||||
@ -89,7 +89,7 @@ pub struct GltfNode {
|
||||
|
||||
/// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive)
|
||||
/// and an optional [`GltfExtras`].
|
||||
#[derive(Debug, Clone, TypeUuid)]
|
||||
#[derive(Debug, Clone, TypeUuid, TypePath)]
|
||||
#[uuid = "8ceaec9a-926a-4f29-8ee3-578a69f42315"]
|
||||
pub struct GltfMesh {
|
||||
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`].
|
||||
#[derive(Debug, Clone, TypeUuid)]
|
||||
#[derive(Debug, Clone, TypeUuid, TypePath)]
|
||||
#[uuid = "cbfca302-82fd-41cb-af77-cab6b3d50af1"]
|
||||
pub struct GltfPrimitive {
|
||||
pub mesh: Handle<Mesh>,
|
||||
|
||||
@ -174,10 +174,12 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use bevy_reflect::TypePath;
|
||||
|
||||
use crate::Input;
|
||||
|
||||
/// Used for testing the functionality of [`Input`].
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(TypePath, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
enum DummyInput {
|
||||
Input1,
|
||||
Input2,
|
||||
|
||||
@ -19,7 +19,7 @@ use bevy_ecs::{
|
||||
SystemParamItem,
|
||||
},
|
||||
};
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_render::{
|
||||
extract_component::ExtractComponentPlugin,
|
||||
mesh::{Mesh, MeshVertexBufferLayout},
|
||||
@ -59,11 +59,11 @@ use std::marker::PhantomData;
|
||||
/// ```
|
||||
/// # use bevy_pbr::{Material, MaterialMeshBundle};
|
||||
/// # 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_asset::{Handle, AssetServer, Assets};
|
||||
///
|
||||
/// #[derive(AsBindGroup, TypeUuid, Debug, Clone)]
|
||||
/// #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
|
||||
/// #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
|
||||
/// pub struct CustomMaterial {
|
||||
/// // 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)
|
||||
/// 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
|
||||
/// will be used.
|
||||
fn vertex_shader() -> ShaderRef {
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
use crate::container_attributes::ReflectTraits;
|
||||
use crate::field_attributes::{parse_field_attrs, ReflectFieldAttr};
|
||||
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 quote::quote;
|
||||
use quote::{quote, ToTokens};
|
||||
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::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> {
|
||||
Struct(ReflectStruct<'a>),
|
||||
@ -36,9 +43,7 @@ pub(crate) struct ReflectMeta<'a> {
|
||||
/// The registered traits for this type.
|
||||
traits: ReflectTraits,
|
||||
/// The name of this type.
|
||||
type_name: &'a Ident,
|
||||
/// The generics defined on this type.
|
||||
generics: &'a Generics,
|
||||
type_path: ReflectTypePath<'a>,
|
||||
/// A cached instance of the path to the `bevy_reflect` crate.
|
||||
bevy_reflect_path: Path,
|
||||
/// The documentation for this type, if any
|
||||
@ -131,8 +136,12 @@ enum ReflectMode {
|
||||
impl<'a> ReflectDerive<'a> {
|
||||
pub fn from_input(input: &'a DeriveInput) -> Result<Self, syn::Error> {
|
||||
let mut traits = ReflectTraits::default();
|
||||
// Should indicate whether `#[reflect_value]` was used
|
||||
// Should indicate whether `#[reflect_value]` was used.
|
||||
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")]
|
||||
let mut doc = crate::documentation::Documentation::default();
|
||||
@ -177,6 +186,35 @@ impl<'a> ReflectDerive<'a> {
|
||||
|
||||
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")]
|
||||
Meta::NameValue(pair) if pair.path.is_ident("doc") => {
|
||||
if let syn::Expr::Lit(syn::ExprLit {
|
||||
@ -190,8 +228,27 @@ impl<'a> ReflectDerive<'a> {
|
||||
_ => 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")]
|
||||
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> {
|
||||
let sifter: utility::ResultSifter<StructField<'a>> = fields
|
||||
.iter()
|
||||
@ -288,11 +355,10 @@ impl<'a> ReflectDerive<'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 {
|
||||
traits,
|
||||
type_name,
|
||||
generics,
|
||||
type_path,
|
||||
bevy_reflect_path: utility::get_bevy_reflect_path(),
|
||||
#[cfg(feature = "documentation")]
|
||||
docs: Default::default(),
|
||||
@ -311,13 +377,8 @@ impl<'a> ReflectMeta<'a> {
|
||||
}
|
||||
|
||||
/// The name of this struct.
|
||||
pub fn type_name(&self) -> &'a Ident {
|
||||
self.type_name
|
||||
}
|
||||
|
||||
/// The generics associated with this struct.
|
||||
pub fn generics(&self) -> &'a Generics {
|
||||
self.generics
|
||||
pub fn type_path(&self) -> &ReflectTypePath<'a> {
|
||||
&self.type_path
|
||||
}
|
||||
|
||||
/// The cached `bevy_reflect` path.
|
||||
@ -330,14 +391,7 @@ impl<'a> ReflectMeta<'a> {
|
||||
&self,
|
||||
where_clause_options: &WhereClauseOptions,
|
||||
) -> proc_macro2::TokenStream {
|
||||
crate::registration::impl_get_type_registration(
|
||||
self.type_name,
|
||||
&self.bevy_reflect_path,
|
||||
self.traits.idents(),
|
||||
self.generics,
|
||||
where_clause_options,
|
||||
None,
|
||||
)
|
||||
crate::registration::impl_get_type_registration(self, where_clause_options, None)
|
||||
}
|
||||
|
||||
/// The collection of docstrings for this type, if any.
|
||||
@ -368,13 +422,8 @@ impl<'a> ReflectStruct<'a> {
|
||||
&self,
|
||||
where_clause_options: &WhereClauseOptions,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let reflect_path = self.meta.bevy_reflect_path();
|
||||
|
||||
crate::registration::impl_get_type_registration(
|
||||
self.meta.type_name(),
|
||||
reflect_path,
|
||||
self.meta.traits().idents(),
|
||||
self.meta.generics(),
|
||||
self.meta(),
|
||||
where_clause_options,
|
||||
Some(&self.serialization_denylist),
|
||||
)
|
||||
@ -421,6 +470,7 @@ impl<'a> ReflectStruct<'a> {
|
||||
active_trait_bounds: quote! { #bevy_reflect_path::Reflect },
|
||||
ignored_types: self.ignored_types().into(),
|
||||
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.
|
||||
pub fn get_unit(&self, variant: &Ident) -> proc_macro2::TokenStream {
|
||||
let name = self.meta.type_name;
|
||||
let name = self.meta.type_path();
|
||||
quote! {
|
||||
#name::#variant
|
||||
}
|
||||
@ -479,6 +529,7 @@ impl<'a> ReflectEnum<'a> {
|
||||
active_trait_bounds: quote! { #bevy_reflect_path::FromReflect },
|
||||
ignored_types: self.ignored_types().into(),
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,13 +22,13 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
|
||||
|
||||
/// Implements `FromReflect` for the given value type
|
||||
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 (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! {
|
||||
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> {
|
||||
#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 {
|
||||
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 ref_value = Ident::new("__param0", Span::call_site());
|
||||
@ -47,8 +47,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
|
||||
variant_constructors,
|
||||
} = get_variant_constructors(reflect_enum, &ref_value, false);
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) =
|
||||
reflect_enum.meta().generics().split_for_impl();
|
||||
let (impl_generics, ty_generics, where_clause) = enum_path.generics().split_for_impl();
|
||||
|
||||
// Add FromReflect bound for each active field
|
||||
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(),
|
||||
active_trait_bounds: quote!(#bevy_reflect_path::FromReflect),
|
||||
ignored_trait_bounds: quote!(#FQDefault),
|
||||
..WhereClauseOptions::type_path_bounds(reflect_enum.meta())
|
||||
},
|
||||
);
|
||||
|
||||
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> {
|
||||
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) {
|
||||
@ -90,8 +90,7 @@ impl MemberValuePair {
|
||||
fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> TokenStream {
|
||||
let fqoption = FQOption.into_token_stream();
|
||||
|
||||
let struct_name = reflect_struct.meta().type_name();
|
||||
let generics = reflect_struct.meta().generics();
|
||||
let struct_path = reflect_struct.meta().type_path();
|
||||
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
|
||||
|
||||
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
|
||||
let where_from_reflect_clause = extend_where_clause(
|
||||
@ -143,11 +146,12 @@ fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> Token
|
||||
} else {
|
||||
quote!(#FQDefault)
|
||||
},
|
||||
..WhereClauseOptions::type_path_bounds(reflect_struct.meta())
|
||||
},
|
||||
);
|
||||
|
||||
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> {
|
||||
if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct) = #bevy_reflect_path::Reflect::reflect_ref(reflect) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::derive_data::{EnumVariant, EnumVariantFields, ReflectEnum, StructField};
|
||||
use crate::enum_utility::{get_variant_constructors, EnumVariantConstructors};
|
||||
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 proc_macro::TokenStream;
|
||||
use proc_macro2::{Ident, Span};
|
||||
@ -10,7 +10,7 @@ use syn::Fields;
|
||||
|
||||
pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
|
||||
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_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")]
|
||||
let info_generator = {
|
||||
@ -77,22 +77,23 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
|
||||
};
|
||||
|
||||
let typed_impl = impl_typed(
|
||||
enum_name,
|
||||
reflect_enum.meta().generics(),
|
||||
reflect_enum.meta(),
|
||||
&where_clause_options,
|
||||
quote! {
|
||||
let variants = [#(#variant_info),*];
|
||||
let info = #info_generator;
|
||||
#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
|
||||
.meta()
|
||||
.get_type_registration(&where_clause_options);
|
||||
|
||||
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);
|
||||
|
||||
@ -101,7 +102,9 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
|
||||
|
||||
#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> {
|
||||
match self {
|
||||
#(#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]
|
||||
fn type_name(&self) -> &str {
|
||||
::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())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
|
||||
self
|
||||
|
||||
@ -7,5 +7,6 @@ mod values;
|
||||
pub(crate) use enums::impl_enum;
|
||||
pub(crate) use structs::impl_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 values::impl_value;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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::ReflectStruct;
|
||||
use proc_macro::TokenStream;
|
||||
@ -10,7 +10,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
|
||||
let fqoption = FQOption.into_token_stream();
|
||||
|
||||
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
|
||||
.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")]
|
||||
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 typed_impl = impl_typed(
|
||||
struct_name,
|
||||
reflect_struct.meta().generics(),
|
||||
reflect_struct.meta(),
|
||||
&where_clause_options,
|
||||
quote! {
|
||||
let fields = [#field_generator];
|
||||
let info = #info_generator;
|
||||
#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 (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);
|
||||
|
||||
@ -105,7 +109,9 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream {
|
||||
|
||||
#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> {
|
||||
match name {
|
||||
#(#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]
|
||||
fn type_name(&self) -> &str {
|
||||
::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())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
|
||||
self
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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::ReflectStruct;
|
||||
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 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
|
||||
.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")]
|
||||
let info_generator = {
|
||||
@ -76,19 +76,22 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
|
||||
};
|
||||
|
||||
let typed_impl = impl_typed(
|
||||
struct_name,
|
||||
reflect_struct.meta().generics(),
|
||||
reflect_struct.meta(),
|
||||
&where_clause_options,
|
||||
quote! {
|
||||
let fields = [#field_generator];
|
||||
let info = #info_generator;
|
||||
#bevy_reflect_path::TypeInfo::TupleStruct(info)
|
||||
},
|
||||
bevy_reflect_path,
|
||||
);
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) =
|
||||
reflect_struct.meta().generics().split_for_impl();
|
||||
let type_path_impl = impl_type_path(reflect_struct.meta(), &where_clause_options);
|
||||
|
||||
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);
|
||||
|
||||
@ -97,7 +100,9 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {
|
||||
|
||||
#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> {
|
||||
match index {
|
||||
#(#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]
|
||||
fn type_name(&self) -> &str {
|
||||
::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())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
|
||||
self
|
||||
|
||||
@ -1,43 +1,149 @@
|
||||
use crate::utility::{extend_where_clause, WhereClauseOptions};
|
||||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use syn::{Generics, Path};
|
||||
use crate::utility::{extend_where_clause, StringExpr, WhereClauseOptions};
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn impl_typed(
|
||||
type_name: &Ident,
|
||||
generics: &Generics,
|
||||
where_clause_options: &WhereClauseOptions,
|
||||
use crate::{
|
||||
derive_data::{ReflectMeta, ReflectTypePath},
|
||||
utility::wrap_in_option,
|
||||
};
|
||||
|
||||
/// Returns an expression for a `NonGenericTypeCell` or `GenericTypeCell` to generate `'static` references.
|
||||
fn static_type_cell(
|
||||
meta: &ReflectMeta,
|
||||
property: TypedProperty,
|
||||
generator: proc_macro2::TokenStream,
|
||||
bevy_reflect_path: &Path,
|
||||
) -> 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! {
|
||||
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, _>(|| {
|
||||
#generator
|
||||
})
|
||||
}
|
||||
} 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! {
|
||||
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(|| {
|
||||
#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
|
||||
let where_reflect_clause = extend_where_clause(where_clause, where_clause_options);
|
||||
|
||||
quote! {
|
||||
impl #impl_generics #bevy_reflect_path::Typed for #type_name #ty_generics #where_reflect_clause {
|
||||
fn type_info() -> &'static #bevy_reflect_path::TypeInfo {
|
||||
#static_generator
|
||||
#primitive_assert
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult};
|
||||
use crate::impls::impl_typed;
|
||||
use crate::utility::WhereClauseOptions;
|
||||
use crate::impls::{impl_type_path, impl_typed};
|
||||
use crate::utility::{extend_where_clause, WhereClauseOptions};
|
||||
use crate::ReflectMeta;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
@ -8,7 +8,7 @@ use quote::quote;
|
||||
/// Implements `GetTypeRegistration` and `Reflect` for the given type data.
|
||||
pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
|
||||
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 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"))]
|
||||
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(
|
||||
type_name,
|
||||
meta.generics(),
|
||||
meta,
|
||||
&where_clause_options,
|
||||
quote! {
|
||||
let info = #bevy_reflect_path::ValueInfo::new::<Self>() #with_docs;
|
||||
#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);
|
||||
|
||||
TokenStream::from(quote! {
|
||||
#get_type_registration_impl
|
||||
|
||||
#type_path_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]
|
||||
fn type_name(&self) -> &str {
|
||||
::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())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn #bevy_reflect_path::DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
|
||||
self
|
||||
|
||||
@ -26,20 +26,27 @@ mod impls;
|
||||
mod reflect_value;
|
||||
mod registration;
|
||||
mod trait_reflection;
|
||||
mod type_path;
|
||||
mod type_uuid;
|
||||
mod utility;
|
||||
|
||||
use crate::derive_data::{ReflectDerive, ReflectMeta, ReflectStruct};
|
||||
use crate::type_uuid::gen_impl_type_uuid;
|
||||
use container_attributes::ReflectTraits;
|
||||
use derive_data::ReflectTypePath;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use reflect_value::ReflectValueDef;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
use type_path::NamedTypePathDef;
|
||||
use type_uuid::TypeUuidDef;
|
||||
use utility::WhereClauseOptions;
|
||||
|
||||
pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
|
||||
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.
|
||||
///
|
||||
@ -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
|
||||
/// 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)]`
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// [`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 {
|
||||
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
|
||||
#[proc_macro_derive(TypeUuid, attributes(uuid))]
|
||||
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
|
||||
/// 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
|
||||
///
|
||||
/// Types can be passed with or without registering type data:
|
||||
///
|
||||
/// ```ignore
|
||||
/// impl_reflect_value!(foo);
|
||||
/// impl_reflect_value!(bar(Debug, Default, Serialize, Deserialize));
|
||||
/// impl_reflect_value!(::my_crate::Foo);
|
||||
/// impl_reflect_value!(::my_crate::Bar(Debug, Default, Serialize, Deserialize));
|
||||
/// ```
|
||||
///
|
||||
/// Generic types can also specify their parameters and bounds:
|
||||
///
|
||||
/// ```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
|
||||
#[proc_macro]
|
||||
pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
|
||||
let def = parse_macro_input!(input as ReflectValueDef);
|
||||
let meta = ReflectMeta::new(
|
||||
&def.type_name,
|
||||
&def.generics,
|
||||
def.traits.unwrap_or_default(),
|
||||
);
|
||||
|
||||
let default_name = &def.type_path.segments.last().unwrap().ident;
|
||||
let type_path = if def.type_path.leading_colon.is_none() && def.custom_path.is_none() {
|
||||
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")]
|
||||
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
|
||||
/// 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
|
||||
/// 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
|
||||
/// be possible to reflect without extending the macro.
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
/// Implementing `Reflect` for `bevy::prelude::Vec3` as a struct type:
|
||||
/// ```ignore
|
||||
/// use bevy::prelude::Vec3;
|
||||
///
|
||||
/// impl_reflect_struct!(
|
||||
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
|
||||
/// struct Vec3 {
|
||||
/// x: f32,
|
||||
/// y: f32,
|
||||
/// z: f32
|
||||
/// }
|
||||
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
|
||||
/// #[type_path = "bevy::prelude"]
|
||||
/// struct Vec3 {
|
||||
/// x: f32,
|
||||
/// y: f32,
|
||||
/// z: f32
|
||||
/// }
|
||||
/// );
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
@ -323,6 +383,15 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
|
||||
|
||||
match derive_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_from_struct: proc_macro2::TokenStream =
|
||||
from_reflect::impl_struct(&struct_data).into();
|
||||
@ -370,11 +439,84 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
|
||||
#[proc_macro]
|
||||
pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
|
||||
let def = parse_macro_input!(input as ReflectValueDef);
|
||||
from_reflect::impl_value(&ReflectMeta::new(
|
||||
&def.type_name,
|
||||
&def.generics,
|
||||
def.traits.unwrap_or_default(),
|
||||
))
|
||||
|
||||
let default_name = &def.type_path.segments.last().unwrap().ident;
|
||||
let type_path = if def.type_path.leading_colon.is_none()
|
||||
&& 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)]`.
|
||||
|
||||
@ -1,58 +1,59 @@
|
||||
use crate::container_attributes::ReflectTraits;
|
||||
use proc_macro2::Ident;
|
||||
use crate::type_path::CustomPathDef;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::token::{Paren, Where};
|
||||
use syn::{parenthesized, Attribute, Generics};
|
||||
use syn::token::Paren;
|
||||
use syn::{parenthesized, Attribute, Generics, Path};
|
||||
|
||||
/// A struct used to define a simple reflected value type (such as primitives).
|
||||
///
|
||||
///
|
||||
///
|
||||
/// This takes the form:
|
||||
///
|
||||
/// ```ignore
|
||||
/// // Standard
|
||||
/// foo(TraitA, TraitB)
|
||||
/// ::my_crate::foo::Bar(TraitA, TraitB)
|
||||
///
|
||||
/// // With generics
|
||||
/// foo<T1: Bar, T2>(TraitA, TraitB)
|
||||
/// ::my_crate::foo::Bar<T1: Bar, T2>(TraitA, TraitB)
|
||||
///
|
||||
/// // 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 {
|
||||
#[allow(dead_code)]
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub type_name: Ident,
|
||||
pub type_path: Path,
|
||||
pub generics: Generics,
|
||||
pub traits: Option<ReflectTraits>,
|
||||
pub custom_path: Option<CustomPathDef>,
|
||||
}
|
||||
|
||||
impl Parse for ReflectValueDef {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let type_ident = input.parse::<Ident>()?;
|
||||
let generics = input.parse::<Generics>()?;
|
||||
let mut lookahead = input.lookahead1();
|
||||
let mut where_clause = None;
|
||||
if lookahead.peek(Where) {
|
||||
where_clause = Some(input.parse()?);
|
||||
lookahead = input.lookahead1();
|
||||
}
|
||||
|
||||
let custom_path = CustomPathDef::parse_parenthesized(input)?;
|
||||
|
||||
let type_path = Path::parse_mod_style(input)?;
|
||||
let mut generics = input.parse::<Generics>()?;
|
||||
generics.where_clause = input.parse()?;
|
||||
|
||||
let mut traits = None;
|
||||
if lookahead.peek(Paren) {
|
||||
if input.peek(Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
traits = Some(content.parse::<ReflectTraits>()?);
|
||||
}
|
||||
|
||||
Ok(ReflectValueDef {
|
||||
attrs,
|
||||
type_name: type_ident,
|
||||
generics: Generics {
|
||||
where_clause,
|
||||
..generics
|
||||
},
|
||||
type_path,
|
||||
generics,
|
||||
traits,
|
||||
custom_path,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,21 +2,21 @@
|
||||
|
||||
use crate::utility::{extend_where_clause, WhereClauseOptions};
|
||||
use bit_set::BitSet;
|
||||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use syn::{Generics, Path};
|
||||
|
||||
use crate::derive_data::ReflectMeta;
|
||||
|
||||
/// Creates the `GetTypeRegistration` impl for the given type data.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn impl_get_type_registration(
|
||||
type_name: &Ident,
|
||||
bevy_reflect_path: &Path,
|
||||
registration_data: &[Ident],
|
||||
generics: &Generics,
|
||||
meta: &ReflectMeta,
|
||||
where_clause_options: &WhereClauseOptions,
|
||||
serialization_denylist: Option<&BitSet<u32>>,
|
||||
) -> 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 denylist = denylist.into_iter();
|
||||
quote! {
|
||||
@ -29,12 +29,12 @@ pub(crate) fn impl_get_type_registration(
|
||||
|
||||
quote! {
|
||||
#[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 {
|
||||
let mut registration = #bevy_reflect_path::TypeRegistration::of::<#type_name #ty_generics>();
|
||||
registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());
|
||||
let mut registration = #bevy_reflect_path::TypeRegistration::of::<Self>();
|
||||
registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<Self>::from_type());
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
||||
102
crates/bevy_reflect/bevy_reflect_derive/src/type_path.rs
Normal file
102
crates/bevy_reflect/bevy_reflect_derive/src/type_path.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
//! 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 bit_set::BitSet;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::quote;
|
||||
use syn::{Member, Path, Type, WhereClause};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{spanned::Spanned, LitStr, Member, Path, Type, WhereClause};
|
||||
|
||||
/// Returns the correct path for `bevy_reflect`.
|
||||
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.
|
||||
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
|
||||
pub(crate) active_types: Box<[Type]>,
|
||||
/// Trait bounds to add to the active types
|
||||
@ -70,12 +74,31 @@ pub(crate) struct WhereClauseOptions {
|
||||
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 {
|
||||
/// By default, don't add any additional bounds to the `where` clause
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
parameter_types: Box::new([]),
|
||||
active_types: Box::new([]),
|
||||
ignored_types: Box::new([]),
|
||||
parameter_trait_bounds: quote! {},
|
||||
active_trait_bounds: quote! {},
|
||||
ignored_trait_bounds: quote! {},
|
||||
}
|
||||
@ -117,22 +140,26 @@ pub(crate) fn extend_where_clause(
|
||||
where_clause: Option<&WhereClause>,
|
||||
where_clause_options: &WhereClauseOptions,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let parameter_types = &where_clause_options.parameter_types;
|
||||
let active_types = &where_clause_options.active_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 ignored_trait_bounds = &where_clause_options.ignored_trait_bounds;
|
||||
|
||||
let mut generic_where_clause = if let Some(where_clause) = where_clause {
|
||||
let predicates = where_clause.predicates.iter();
|
||||
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}
|
||||
} else {
|
||||
quote! {}
|
||||
quote!()
|
||||
};
|
||||
generic_where_clause.extend(quote! {
|
||||
#(#active_types: #active_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
|
||||
}
|
||||
@ -212,3 +239,118 @@ where
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
@ -221,6 +226,11 @@ impl Reflect for DynamicArray {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
@ -335,6 +345,7 @@ impl Array for DynamicArray {
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicArray);
|
||||
/// An iterator over an [`Array`].
|
||||
pub struct ArrayIter<'a> {
|
||||
array: &'a dyn Array,
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
use crate::{
|
||||
enum_debug, enum_hash, enum_partial_eq, DynamicStruct, DynamicTuple, Enum, Reflect, ReflectMut,
|
||||
ReflectOwned, ReflectRef, Struct, Tuple, TypeInfo, VariantFieldIter, VariantType,
|
||||
self as bevy_reflect, enum_debug, enum_hash, enum_partial_eq, DynamicStruct, DynamicTuple,
|
||||
DynamicTypePath, Enum, Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple, TypeInfo,
|
||||
VariantFieldIter, VariantType,
|
||||
};
|
||||
use std::any::Any;
|
||||
use std::fmt::Formatter;
|
||||
@ -297,6 +300,11 @@ impl Reflect for DynamicEnum {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
@ -420,3 +428,5 @@ impl Reflect for DynamicEnum {
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicEnum);
|
||||
|
||||
@ -6,6 +6,7 @@ use glam::*;
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, Hash, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct IVec2 {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -13,6 +14,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, Hash, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct IVec3 {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -21,6 +23,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, Hash, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct IVec4 {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -31,6 +34,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, Hash, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct UVec2 {
|
||||
x: u32,
|
||||
y: u32,
|
||||
@ -38,6 +42,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, Hash, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct UVec3 {
|
||||
x: u32,
|
||||
y: u32,
|
||||
@ -46,6 +51,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, Hash, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct UVec4 {
|
||||
x: u32,
|
||||
y: u32,
|
||||
@ -53,9 +59,9 @@ impl_reflect_struct!(
|
||||
w: u32,
|
||||
}
|
||||
);
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Vec2 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
@ -63,6 +69,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Vec3 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
@ -71,6 +78,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Vec3A {
|
||||
x: f32,
|
||||
y: f32,
|
||||
@ -79,6 +87,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Vec4 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
@ -89,6 +98,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct BVec2 {
|
||||
x: bool,
|
||||
y: bool,
|
||||
@ -96,6 +106,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct BVec3 {
|
||||
x: bool,
|
||||
y: bool,
|
||||
@ -104,6 +115,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct BVec4 {
|
||||
x: bool,
|
||||
y: bool,
|
||||
@ -114,6 +126,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DVec2 {
|
||||
x: f64,
|
||||
y: f64,
|
||||
@ -121,6 +134,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DVec3 {
|
||||
x: f64,
|
||||
y: f64,
|
||||
@ -129,6 +143,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DVec4 {
|
||||
x: f64,
|
||||
y: f64,
|
||||
@ -139,6 +154,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Mat2 {
|
||||
x_axis: Vec2,
|
||||
y_axis: Vec2,
|
||||
@ -146,6 +162,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Mat3 {
|
||||
x_axis: Vec3,
|
||||
y_axis: Vec3,
|
||||
@ -154,6 +171,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Mat3A {
|
||||
x_axis: Vec3A,
|
||||
y_axis: Vec3A,
|
||||
@ -162,6 +180,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Mat4 {
|
||||
x_axis: Vec4,
|
||||
y_axis: Vec4,
|
||||
@ -172,6 +191,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DMat2 {
|
||||
x_axis: DVec2,
|
||||
y_axis: DVec2,
|
||||
@ -179,6 +199,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DMat3 {
|
||||
x_axis: DVec3,
|
||||
y_axis: DVec3,
|
||||
@ -187,6 +208,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DMat4 {
|
||||
x_axis: DVec4,
|
||||
y_axis: DVec4,
|
||||
@ -197,6 +219,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Affine2 {
|
||||
matrix2: Mat2,
|
||||
translation: Vec2,
|
||||
@ -204,6 +227,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct Affine3A {
|
||||
matrix3: Mat3A,
|
||||
translation: Vec3A,
|
||||
@ -212,6 +236,7 @@ impl_reflect_struct!(
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DAffine2 {
|
||||
matrix2: DMat2,
|
||||
translation: DVec2,
|
||||
@ -219,6 +244,7 @@ impl_reflect_struct!(
|
||||
);
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Default)]
|
||||
#[type_path = "glam"]
|
||||
struct DAffine3 {
|
||||
matrix3: DMat3,
|
||||
translation: DVec3,
|
||||
@ -229,12 +255,24 @@ impl_reflect_struct!(
|
||||
// mechanisms for read-only fields. I doubt those mechanisms would be added,
|
||||
// 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.
|
||||
impl_reflect_value!(Quat(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||
impl_reflect_value!(DQuat(Debug, PartialEq, Serialize, Deserialize, Default));
|
||||
impl_reflect_value!(::glam::Quat(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Default
|
||||
));
|
||||
impl_reflect_value!(::glam::DQuat(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Default
|
||||
));
|
||||
|
||||
impl_from_reflect_value!(Quat);
|
||||
impl_from_reflect_value!(DQuat);
|
||||
|
||||
impl_reflect_value!(EulerRot(Debug, Default));
|
||||
impl_reflect_value!(BVec3A(Debug, Default));
|
||||
impl_reflect_value!(BVec4A(Debug, Default));
|
||||
impl_reflect_value!(::glam::EulerRot(Debug, Default));
|
||||
impl_reflect_value!(::glam::BVec3A(Debug, Default));
|
||||
impl_reflect_value!(::glam::BVec4A(Debug, Default));
|
||||
|
||||
@ -6,6 +6,7 @@ use bevy_reflect_derive::impl_reflect_struct;
|
||||
|
||||
impl_reflect_struct!(
|
||||
#[reflect(Debug, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[type_path = "bevy_math"]
|
||||
struct Rect {
|
||||
min: Vec2,
|
||||
max: Vec2,
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
use smallvec::SmallVec;
|
||||
use std::any::Any;
|
||||
|
||||
use crate::utility::GenericTypeInfoCell;
|
||||
use crate::{
|
||||
FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Reflect, ReflectFromPtr,
|
||||
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeRegistration, Typed,
|
||||
self as bevy_reflect, DynamicTypePath, FromReflect, FromType, GetTypeRegistration, List,
|
||||
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
|
||||
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
|
||||
T::Item: FromReflect,
|
||||
{
|
||||
@ -86,6 +88,11 @@ where
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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
|
||||
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
|
||||
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
|
||||
T::Item: FromReflect,
|
||||
{
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
use crate::std_traits::ReflectDefault;
|
||||
use crate::{self as bevy_reflect, ReflectFromPtr, ReflectFromReflect, ReflectOwned};
|
||||
use crate::{
|
||||
map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum, DynamicMap, Enum,
|
||||
EnumInfo, FromReflect, FromType, GetTypeRegistration, List, ListInfo, Map, MapInfo, MapIter,
|
||||
Reflect, ReflectDeserialize, ReflectMut, ReflectRef, ReflectSerialize, TupleVariantInfo,
|
||||
TypeInfo, TypeRegistration, Typed, UnitVariantInfo, UnnamedField, ValueInfo, VariantFieldIter,
|
||||
VariantInfo, VariantType,
|
||||
impl_type_path, map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum,
|
||||
DynamicMap, DynamicTypePath, Enum, EnumInfo, FromReflect, FromType, GetTypeRegistration, List,
|
||||
ListInfo, ListIter, Map, MapInfo, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef,
|
||||
ReflectSerialize, TupleVariantInfo, TypeInfo, TypePath, TypeRegistration, Typed,
|
||||
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_utils::HashSet;
|
||||
use bevy_utils::{Duration, Instant};
|
||||
@ -93,7 +95,7 @@ impl_reflect_value!(String(
|
||||
Deserialize,
|
||||
Default
|
||||
));
|
||||
impl_reflect_value!(PathBuf(
|
||||
impl_reflect_value!(::std::path::PathBuf(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
@ -101,15 +103,18 @@ impl_reflect_value!(PathBuf(
|
||||
Deserialize,
|
||||
Default
|
||||
));
|
||||
impl_reflect_value!(Result<T: Clone + Reflect + 'static, E: Clone + Reflect + 'static>());
|
||||
impl_reflect_value!(HashSet<T: Hash + Eq + Clone + Send + Sync + 'static>());
|
||||
impl_reflect_value!(Range<T: Clone + Send + Sync + 'static>());
|
||||
impl_reflect_value!(RangeInclusive<T: Clone + Send + Sync + 'static>());
|
||||
impl_reflect_value!(RangeFrom<T: Clone + Send + Sync + 'static>());
|
||||
impl_reflect_value!(RangeTo<T: Clone + Send + Sync + 'static>());
|
||||
impl_reflect_value!(RangeToInclusive<T: Clone + Send + Sync + 'static>());
|
||||
impl_reflect_value!(RangeFull());
|
||||
impl_reflect_value!(Duration(
|
||||
impl_reflect_value!(
|
||||
::core::result::Result < T: Clone + Reflect + TypePath,
|
||||
E: Clone + Reflect + TypePath > ()
|
||||
);
|
||||
impl_reflect_value!(::bevy_utils::HashSet<T: Hash + Eq + Clone + Send + Sync>());
|
||||
impl_reflect_value!(::core::ops::Range<T: Clone + Send + Sync>());
|
||||
impl_reflect_value!(::core::ops::RangeInclusive<T: Clone + Send + Sync>());
|
||||
impl_reflect_value!(::core::ops::RangeFrom<T: Clone + Send + Sync>());
|
||||
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,
|
||||
Hash,
|
||||
PartialEq,
|
||||
@ -117,26 +122,104 @@ impl_reflect_value!(Duration(
|
||||
Deserialize,
|
||||
Default
|
||||
));
|
||||
impl_reflect_value!(Instant(Debug, Hash, PartialEq));
|
||||
impl_reflect_value!(NonZeroI128(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroU128(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroIsize(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroUsize(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroI64(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroU64(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroU32(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroI32(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroI16(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroU16(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroU8(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(NonZeroI8(Debug, Hash, PartialEq, Serialize, Deserialize));
|
||||
impl_reflect_value!(::bevy_utils::Instant(Debug, Hash, PartialEq));
|
||||
impl_reflect_value!(::core::num::NonZeroI128(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize
|
||||
));
|
||||
impl_reflect_value!(::core::num::NonZeroU128(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
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:
|
||||
// https://github.com/serde-rs/serde/blob/3ffb86fc70efd3d329519e2dddfa306cc04f167c/serde/src/de/impls.rs#L1732
|
||||
#[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)))]
|
||||
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!(char);
|
||||
@ -157,12 +240,12 @@ impl_from_reflect_value!(f64);
|
||||
impl_from_reflect_value!(String);
|
||||
impl_from_reflect_value!(PathBuf);
|
||||
impl_from_reflect_value!(OsString);
|
||||
impl_from_reflect_value!(HashSet<T: Hash + Eq + Clone + Send + Sync + 'static>);
|
||||
impl_from_reflect_value!(Range<T: Clone + Send + Sync + 'static>);
|
||||
impl_from_reflect_value!(RangeInclusive<T: Clone + Send + Sync + 'static>);
|
||||
impl_from_reflect_value!(RangeFrom<T: Clone + Send + Sync + 'static>);
|
||||
impl_from_reflect_value!(RangeTo<T: Clone + Send + Sync + 'static>);
|
||||
impl_from_reflect_value!(RangeToInclusive<T: Clone + Send + Sync + 'static>);
|
||||
impl_from_reflect_value!(HashSet<T: TypePath + Hash + Eq + Clone + Send + Sync>);
|
||||
impl_from_reflect_value!(Range<T: TypePath + Clone + Send + Sync>);
|
||||
impl_from_reflect_value!(RangeInclusive<T: TypePath + Clone + Send + Sync>);
|
||||
impl_from_reflect_value!(RangeFrom<T: TypePath + Clone + Send + Sync>);
|
||||
impl_from_reflect_value!(RangeTo<T: TypePath + Clone + Send + Sync>);
|
||||
impl_from_reflect_value!(RangeToInclusive<T: TypePath + Clone + Send + Sync>);
|
||||
impl_from_reflect_value!(RangeFull);
|
||||
impl_from_reflect_value!(Duration);
|
||||
impl_from_reflect_value!(Instant);
|
||||
@ -180,8 +263,8 @@ impl_from_reflect_value!(NonZeroU8);
|
||||
impl_from_reflect_value!(NonZeroI8);
|
||||
|
||||
macro_rules! impl_reflect_for_veclike {
|
||||
($ty:ty, $insert:expr, $remove:expr, $push:expr, $pop:expr, $sub:ty) => {
|
||||
impl<T: FromReflect> List for $ty {
|
||||
($ty:path, $insert:expr, $remove:expr, $push:expr, $pop:expr, $sub:ty) => {
|
||||
impl<T: FromReflect + TypePath> List for $ty {
|
||||
#[inline]
|
||||
fn get(&self, index: usize) -> Option<&dyn Reflect> {
|
||||
<$sub>::get(self, index).map(|value| value as &dyn Reflect)
|
||||
@ -228,8 +311,8 @@ macro_rules! impl_reflect_for_veclike {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn iter(&self) -> $crate::ListIter {
|
||||
$crate::ListIter::new(self)
|
||||
fn iter(&self) -> ListIter {
|
||||
ListIter::new(self)
|
||||
}
|
||||
|
||||
#[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 {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
@ -249,6 +332,11 @@ macro_rules! impl_reflect_for_veclike {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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 {
|
||||
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
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 {
|
||||
let mut registration = TypeRegistration::of::<$ty>();
|
||||
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> {
|
||||
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
|
||||
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!(
|
||||
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::remove,
|
||||
VecDeque::push_back,
|
||||
@ -349,12 +446,12 @@ impl_reflect_for_veclike!(
|
||||
);
|
||||
|
||||
macro_rules! impl_reflect_for_hashmap {
|
||||
($ty:ty) => {
|
||||
($ty:path) => {
|
||||
impl<K, V, S> Map for $ty
|
||||
where
|
||||
K: FromReflect + Eq + Hash,
|
||||
V: FromReflect,
|
||||
S: BuildHasher + Send + Sync + 'static,
|
||||
K: FromReflect + TypePath + Eq + Hash,
|
||||
V: FromReflect + TypePath,
|
||||
S: TypePath + BuildHasher + Send + Sync,
|
||||
{
|
||||
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
|
||||
key.downcast_ref::<K>()
|
||||
@ -446,9 +543,9 @@ macro_rules! impl_reflect_for_hashmap {
|
||||
|
||||
impl<K, V, S> Reflect for $ty
|
||||
where
|
||||
K: FromReflect + Eq + Hash,
|
||||
V: FromReflect,
|
||||
S: BuildHasher + Send + Sync + 'static,
|
||||
K: FromReflect + TypePath + Eq + Hash,
|
||||
V: FromReflect + TypePath,
|
||||
S: TypePath + BuildHasher + Send + Sync,
|
||||
{
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
@ -458,6 +555,10 @@ macro_rules! impl_reflect_for_hashmap {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
@ -515,9 +616,9 @@ macro_rules! impl_reflect_for_hashmap {
|
||||
|
||||
impl<K, V, S> Typed for $ty
|
||||
where
|
||||
K: FromReflect + Eq + Hash,
|
||||
V: FromReflect,
|
||||
S: BuildHasher + Send + Sync + 'static,
|
||||
K: FromReflect + TypePath + Eq + Hash,
|
||||
V: FromReflect + TypePath,
|
||||
S: TypePath + BuildHasher + Send + Sync,
|
||||
{
|
||||
fn type_info() -> &'static TypeInfo {
|
||||
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
@ -527,9 +628,9 @@ macro_rules! impl_reflect_for_hashmap {
|
||||
|
||||
impl<K, V, S> GetTypeRegistration for $ty
|
||||
where
|
||||
K: FromReflect + Eq + Hash,
|
||||
V: FromReflect,
|
||||
S: BuildHasher + Send + Sync + 'static,
|
||||
K: FromReflect + TypePath + Eq + Hash,
|
||||
V: FromReflect + TypePath,
|
||||
S: TypePath + BuildHasher + Send + Sync,
|
||||
{
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
let mut registration = TypeRegistration::of::<Self>();
|
||||
@ -540,9 +641,9 @@ macro_rules! impl_reflect_for_hashmap {
|
||||
|
||||
impl<K, V, S> FromReflect for $ty
|
||||
where
|
||||
K: FromReflect + Eq + Hash,
|
||||
V: FromReflect,
|
||||
S: BuildHasher + Default + Send + Sync + 'static,
|
||||
K: FromReflect + TypePath + Eq + Hash,
|
||||
V: FromReflect + TypePath,
|
||||
S: TypePath + BuildHasher + Default + Send + Sync,
|
||||
{
|
||||
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
|
||||
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]
|
||||
fn get(&self, index: usize) -> Option<&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]
|
||||
fn type_name(&self) -> &str {
|
||||
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())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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> {
|
||||
if let ReflectRef::Array(ref_array) = reflect.reflect_ref() {
|
||||
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 {
|
||||
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
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:
|
||||
// `FromType::from_type` requires `Deserialize<'de>` to be implemented for `T`.
|
||||
// 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 {
|
||||
($($N:expr)+) => {
|
||||
$(
|
||||
impl<T: Reflect > GetTypeRegistration for [T; $N] {
|
||||
impl<T: Reflect + TypePath> GetTypeRegistration for [T; $N] {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
TypeRegistration::of::<[T; $N]>()
|
||||
}
|
||||
@ -720,13 +855,13 @@ impl_array_get_type_registration! {
|
||||
30 31 32
|
||||
}
|
||||
|
||||
impl<T: FromReflect> GetTypeRegistration for Option<T> {
|
||||
impl<T: FromReflect + TypePath> GetTypeRegistration for Option<T> {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
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> {
|
||||
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]
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
@ -808,6 +943,11 @@ impl<T: FromReflect> Reflect for Option<T> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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> {
|
||||
if let ReflectRef::Enum(dyn_enum) = reflect.reflect_ref() {
|
||||
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 {
|
||||
static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
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> {
|
||||
fn type_name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
@ -973,6 +1115,11 @@ impl Reflect for Cow<'static, str> {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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> {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
let mut registration = TypeRegistration::of::<Cow<'static, str>>();
|
||||
@ -1081,6 +1252,11 @@ impl Reflect for &'static Path {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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 {
|
||||
fn get_type_registration() -> TypeRegistration {
|
||||
let mut registration = TypeRegistration::of::<Self>();
|
||||
@ -1178,6 +1366,11 @@ impl Reflect for Cow<'static, Path> {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
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> {
|
||||
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
|
||||
Some(reflect.as_any().downcast_ref::<Self>()?.clone())
|
||||
|
||||
@ -448,6 +448,7 @@ mod struct_trait;
|
||||
mod tuple;
|
||||
mod tuple_struct;
|
||||
mod type_info;
|
||||
mod type_path;
|
||||
mod type_registry;
|
||||
mod type_uuid;
|
||||
mod type_uuid_impl;
|
||||
@ -496,12 +497,15 @@ pub use struct_trait::*;
|
||||
pub use tuple::*;
|
||||
pub use tuple_struct::*;
|
||||
pub use type_info::*;
|
||||
pub use type_path::*;
|
||||
pub use type_registry::*;
|
||||
pub use type_uuid::*;
|
||||
|
||||
pub use bevy_reflect_derive::*;
|
||||
pub use erased_serde;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod __macro_exports {
|
||||
use crate::Uuid;
|
||||
@ -543,8 +547,8 @@ mod tests {
|
||||
ser::{to_string_pretty, PrettyConfig},
|
||||
Deserializer,
|
||||
};
|
||||
use std::any::TypeId;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::{any::TypeId, marker::PhantomData};
|
||||
|
||||
use super::prelude::*;
|
||||
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]
|
||||
fn reflect_type_info() {
|
||||
// TypeInfo
|
||||
@ -1171,7 +1267,7 @@ mod tests {
|
||||
|
||||
// Struct (generic)
|
||||
#[derive(Reflect)]
|
||||
struct MyGenericStruct<T: Reflect> {
|
||||
struct MyGenericStruct<T: Reflect + TypePath> {
|
||||
foo: T,
|
||||
bar: usize,
|
||||
}
|
||||
@ -1420,7 +1516,7 @@ mod tests {
|
||||
struct SomePrimitive;
|
||||
impl_reflect_value!(
|
||||
/// Some primitive for which we have attributed custom documentation.
|
||||
SomePrimitive
|
||||
(in bevy_reflect::tests) SomePrimitive
|
||||
);
|
||||
|
||||
let info = <SomePrimitive as Typed>::type_info();
|
||||
|
||||
@ -2,8 +2,13 @@ use std::any::{Any, TypeId};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
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].
|
||||
///
|
||||
@ -271,6 +276,11 @@ impl Reflect for DynamicList {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
@ -352,6 +362,8 @@ impl Reflect for DynamicList {
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicList);
|
||||
|
||||
impl Debug for DynamicList {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.debug(f)
|
||||
|
||||
@ -2,9 +2,12 @@ use std::any::{Any, TypeId};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::hash::Hash;
|
||||
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
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].
|
||||
///
|
||||
@ -307,6 +310,11 @@ impl Reflect for DynamicMap {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
}
|
||||
@ -375,6 +383,8 @@ impl Reflect for DynamicMap {
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicMap);
|
||||
|
||||
impl Debug for DynamicMap {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.debug(f)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
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,
|
||||
ValueInfo,
|
||||
tuple_struct_debug, Array, DynamicTypePath, Enum, List, Map, Struct, Tuple, TupleStruct,
|
||||
TypeInfo, Typed, ValueInfo,
|
||||
};
|
||||
use std::{
|
||||
any::{self, Any, TypeId},
|
||||
@ -93,6 +93,14 @@ pub trait Reflect: Any + Send + Sync {
|
||||
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
|
||||
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].
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any>;
|
||||
|
||||
|
||||
@ -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 std::fmt::{Debug, Formatter};
|
||||
use std::{
|
||||
@ -401,6 +405,11 @@ impl Reflect for DynamicStruct {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
@ -485,6 +494,8 @@ impl Reflect for DynamicStruct {
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicStruct);
|
||||
|
||||
impl Debug for DynamicStruct {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.debug(f)
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
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,
|
||||
};
|
||||
use std::any::{Any, TypeId};
|
||||
@ -318,6 +321,11 @@ impl Reflect for DynamicTuple {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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`.
|
||||
///
|
||||
/// # Panics
|
||||
@ -467,7 +477,7 @@ pub fn tuple_debug(dyn_tuple: &dyn Tuple, f: &mut std::fmt::Formatter<'_>) -> st
|
||||
|
||||
macro_rules! impl_reflect_tuple {
|
||||
{$($index:tt : $name:tt),*} => {
|
||||
impl<$($name: Reflect),*> Tuple for ($($name,)*) {
|
||||
impl<$($name: Reflect + TypePath),*> Tuple for ($($name,)*) {
|
||||
#[inline]
|
||||
fn field(&self, index: usize) -> Option<&dyn Reflect> {
|
||||
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 {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
@ -528,6 +538,11 @@ macro_rules! impl_reflect_tuple {
|
||||
Some(<Self as Typed>::type_info())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
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 {
|
||||
static CELL: $crate::utility::GenericTypeInfoCell = $crate::utility::GenericTypeInfoCell::new();
|
||||
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 {
|
||||
TypeRegistration::of::<($($name,)*)>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($name: FromReflect),*> FromReflect for ($($name,)*)
|
||||
impl<$($name: FromReflect + TypePath),*> FromReflect for ($($name,)*)
|
||||
{
|
||||
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
|
||||
if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() {
|
||||
|
||||
@ -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::fmt::{Debug, Formatter};
|
||||
use std::slice::Iter;
|
||||
@ -303,6 +308,11 @@ impl Reflect for DynamicTupleStruct {
|
||||
self.represented_type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_type_path(&self) -> &dyn DynamicTypePath {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_any(self: Box<Self>) -> Box<dyn Any> {
|
||||
self
|
||||
@ -386,6 +396,8 @@ impl Reflect for DynamicTupleStruct {
|
||||
}
|
||||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicTupleStruct);
|
||||
|
||||
impl Debug for DynamicTupleStruct {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.debug(f)
|
||||
|
||||
@ -24,7 +24,7 @@ use std::fmt::Debug;
|
||||
///
|
||||
/// ```
|
||||
/// # 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::Typed;
|
||||
///
|
||||
@ -51,6 +51,7 @@ use std::fmt::Debug;
|
||||
/// # impl Reflect for MyStruct {
|
||||
/// # 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 as_any(&self) -> &dyn Any { todo!() }
|
||||
/// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() }
|
||||
|
||||
167
crates/bevy_reflect/src/type_path.rs
Normal file
167
crates/bevy_reflect/src/type_path.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
@ -9,132 +9,220 @@ use std::{
|
||||
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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Non-generic [`TypePath`]s should be trivially generated with string literals and [`concat!`].
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// # 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;
|
||||
///
|
||||
/// struct Foo {
|
||||
/// bar: i32
|
||||
/// bar: i32
|
||||
/// }
|
||||
///
|
||||
/// impl Typed for Foo {
|
||||
/// fn type_info() -> &'static TypeInfo {
|
||||
/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
|
||||
/// CELL.get_or_set(|| {
|
||||
/// let fields = [NamedField::new::<i32>("bar")];
|
||||
/// let info = StructInfo::new::<Self>("Foo", &fields);
|
||||
/// TypeInfo::Struct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// fn type_info() -> &'static TypeInfo {
|
||||
/// static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
|
||||
/// CELL.get_or_set(|| {
|
||||
/// let fields = [NamedField::new::<i32>("bar")];
|
||||
/// let info = StructInfo::new::<Self>("Foo", &fields);
|
||||
/// TypeInfo::Struct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # impl Reflect for Foo {
|
||||
/// # fn type_name(&self) -> &str { 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!() }
|
||||
/// # 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!() }
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct NonGenericTypeInfoCell(OnceBox<TypeInfo>);
|
||||
///
|
||||
/// [`TypePath`]: crate::TypePath
|
||||
pub struct NonGenericTypeCell<T: TypedProperty>(OnceBox<T::Stored>);
|
||||
|
||||
impl NonGenericTypeInfoCell {
|
||||
/// Initialize a [`NonGenericTypeInfoCell`] for non-generic types.
|
||||
/// See [`NonGenericTypeCell`].
|
||||
pub type NonGenericTypeInfoCell = NonGenericTypeCell<TypeInfo>;
|
||||
|
||||
impl<T: TypedProperty> NonGenericTypeCell<T> {
|
||||
/// Initialize a [`NonGenericTypeCell`] for non-generic types.
|
||||
pub const fn new() -> Self {
|
||||
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.
|
||||
///
|
||||
/// [`TypeInfos`]: TypeInfo
|
||||
pub fn get_or_set<F>(&self, f: F) -> &TypeInfo
|
||||
/// 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
|
||||
where
|
||||
F: FnOnce() -> TypeInfo,
|
||||
F: FnOnce() -> T::Stored,
|
||||
{
|
||||
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,
|
||||
/// 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 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;
|
||||
///
|
||||
/// struct Foo<T: Reflect>(T);
|
||||
/// struct Foo<T>(T);
|
||||
///
|
||||
/// impl<T: Reflect> Typed for Foo<T> {
|
||||
/// fn type_info() -> &'static TypeInfo {
|
||||
/// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
/// CELL.get_or_insert::<Self, _>(|| {
|
||||
/// let fields = [UnnamedField::new::<T>(0)];
|
||||
/// let info = TupleStructInfo::new::<Self>("Foo", &fields);
|
||||
/// TypeInfo::TupleStruct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// fn type_info() -> &'static TypeInfo {
|
||||
/// static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new();
|
||||
/// CELL.get_or_insert::<Self, _>(|| {
|
||||
/// let fields = [UnnamedField::new::<T>(0)];
|
||||
/// let info = TupleStructInfo::new::<Self>("Foo", &fields);
|
||||
/// TypeInfo::TupleStruct(info)
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # impl<T: Reflect> Reflect for Foo<T> {
|
||||
/// # fn type_name(&self) -> &str { 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!() }
|
||||
/// # 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!() }
|
||||
/// # }
|
||||
/// ```
|
||||
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 {
|
||||
/// Initialize a [`GenericTypeInfoCell`] for generic types.
|
||||
/// See [`GenericTypeCell`].
|
||||
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 {
|
||||
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`.
|
||||
/// If there is no [`TypeInfo`] found, a new one will be generated from the given function.
|
||||
pub fn get_or_insert<T, F>(&self, f: F) -> &TypeInfo
|
||||
/// This method will then return the correct [`TypedProperty`] reference for the given type `T`.
|
||||
/// If there is no entry found, a new one will be generated from the given function.
|
||||
pub fn get_or_insert<G, F>(&self, f: F) -> &T::Stored
|
||||
where
|
||||
T: Any + ?Sized,
|
||||
F: FnOnce() -> TypeInfo,
|
||||
G: Any + ?Sized,
|
||||
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::default);
|
||||
if let Some(info) = mapping.read().get(&type_id) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_reflect::{Reflect, TypePath};
|
||||
|
||||
#[derive(Reflect)]
|
||||
struct Foo<T> {
|
||||
@ -6,10 +6,11 @@ struct Foo<T> {
|
||||
}
|
||||
|
||||
// Type that doesn't implement Reflect
|
||||
#[derive(TypePath)]
|
||||
struct NoReflect(f32);
|
||||
|
||||
fn main() {
|
||||
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.get_field::<NoReflect>("a").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
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>`
|
||||
|
||||
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`
|
||||
|
|
||||
= help: the following other types implement trait `Reflect`:
|
||||
|
||||
@ -12,7 +12,7 @@ use bevy_core::cast_slice;
|
||||
use bevy_derive::EnumVariantMeta;
|
||||
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
|
||||
use bevy_math::*;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_utils::{tracing::error, Hashed};
|
||||
use std::{collections::BTreeMap, hash::Hash, iter::FusedIterator};
|
||||
use thiserror::Error;
|
||||
@ -25,7 +25,7 @@ pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
|
||||
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
|
||||
|
||||
// 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"]
|
||||
pub struct Mesh {
|
||||
primitive_topology: PrimitiveTopology,
|
||||
|
||||
@ -6,7 +6,7 @@ use bevy_ecs::{
|
||||
reflect::ReflectMapEntities,
|
||||
};
|
||||
use bevy_math::Mat4;
|
||||
use bevy_reflect::{Reflect, TypeUuid};
|
||||
use bevy_reflect::{Reflect, TypePath, TypeUuid};
|
||||
use std::ops::Deref;
|
||||
|
||||
#[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"]
|
||||
pub struct SkinnedMeshInverseBindposes(Box<[Mat4]>);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use super::ShaderDefVal;
|
||||
use crate::define_atomic_id;
|
||||
use bevy_asset::{AssetLoader, AssetPath, Handle, LoadContext, LoadedAsset};
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_utils::{tracing::error, BoxedFuture, HashMap};
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
use naga::back::wgsl::WriterFlags;
|
||||
@ -31,7 +31,7 @@ pub enum ShaderReflectError {
|
||||
}
|
||||
/// A shader, as defined by its [`ShaderSource`] and [`ShaderStage`](naga::ShaderStage)
|
||||
/// 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"]
|
||||
pub struct Shader {
|
||||
source: Source,
|
||||
|
||||
@ -69,7 +69,7 @@ bitflags::bitflags! {
|
||||
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);
|
||||
|
||||
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
|
||||
|
||||
@ -8,7 +8,7 @@ use bevy_ecs::{
|
||||
reflect::{ReflectComponent, ReflectMapEntities},
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::{Reflect, TypeRegistryArc, TypeUuid};
|
||||
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc, TypeUuid};
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
#[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
|
||||
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
|
||||
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
|
||||
#[derive(Default, TypeUuid)]
|
||||
#[derive(Default, TypeUuid, TypePath)]
|
||||
#[uuid = "749479b1-fb8c-4ff8-a775-623aa76014f5"]
|
||||
pub struct DynamicScene {
|
||||
pub resources: Vec<Box<dyn Reflect>>,
|
||||
|
||||
@ -4,7 +4,7 @@ use bevy_ecs::{
|
||||
reflect::{ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
|
||||
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
|
||||
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
|
||||
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
|
||||
#[derive(Debug, TypeUuid)]
|
||||
#[derive(Debug, TypeUuid, TypePath)]
|
||||
#[uuid = "c156503c-edd9-4ec7-8d33-dab392df03cd"]
|
||||
pub struct Scene {
|
||||
pub world: World,
|
||||
|
||||
@ -14,7 +14,7 @@ use bevy_ecs::{
|
||||
},
|
||||
};
|
||||
use bevy_log::error;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_render::{
|
||||
extract_component::ExtractComponentPlugin,
|
||||
mesh::{Mesh, MeshVertexBufferLayout},
|
||||
@ -60,11 +60,11 @@ use crate::{
|
||||
/// ```
|
||||
/// # use bevy_sprite::{Material2d, MaterialMesh2dBundle};
|
||||
/// # 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_asset::{Handle, AssetServer, Assets};
|
||||
///
|
||||
/// #[derive(AsBindGroup, TypeUuid, Debug, Clone)]
|
||||
/// #[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
|
||||
/// #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
|
||||
/// pub struct CustomMaterial {
|
||||
/// // Uniform bindings must implement `ShaderType`, which will be used to convert the value to
|
||||
@ -111,7 +111,7 @@ use crate::{
|
||||
/// @group(1) @binding(2)
|
||||
/// 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
|
||||
/// will be used.
|
||||
fn vertex_shader() -> ShaderRef {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use ab_glyph::{FontArc, FontVec, InvalidFont, OutlinedGlyph};
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_reflect::{TypePath, TypeUuid};
|
||||
use bevy_render::{
|
||||
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
||||
texture::Image,
|
||||
};
|
||||
|
||||
#[derive(Debug, TypeUuid, Clone)]
|
||||
#[derive(Debug, TypeUuid, TypePath, Clone)]
|
||||
#[uuid = "97059ac6-c9ba-4da9-95b6-bed82c3ce198"]
|
||||
pub struct Font {
|
||||
pub font: FontArc,
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::{error::TextError, Font, FontAtlas};
|
||||
use ab_glyph::{GlyphId, OutlinedGlyph, Point};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_math::Vec2;
|
||||
use bevy_reflect::TypePath;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_render::texture::Image;
|
||||
use bevy_sprite::TextureAtlas;
|
||||
@ -10,7 +11,7 @@ use bevy_utils::HashMap;
|
||||
|
||||
type FontSizeKey = FloatOrd;
|
||||
|
||||
#[derive(TypeUuid)]
|
||||
#[derive(TypeUuid, TypePath)]
|
||||
#[uuid = "73ba778b-b6b5-4f45-982d-d21b6b86ace2"]
|
||||
pub struct FontAtlasSet {
|
||||
font_atlases: HashMap<FontSizeKey, Vec<FontAtlas>>,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use bevy::gltf::GltfPlugin;
|
||||
use bevy::prelude::*;
|
||||
use bevy::reflect::TypeUuid;
|
||||
use bevy::reflect::{TypePath, TypeUuid};
|
||||
use bevy::render::mesh::{MeshVertexAttribute, MeshVertexBufferLayout};
|
||||
use bevy::render::render_resource::*;
|
||||
use bevy::sprite::{
|
||||
@ -55,7 +55,7 @@ fn setup(
|
||||
/// This custom material uses barycentric coordinates from
|
||||
/// `ATTRIBUTE_BARYCENTRIC` to shade a white border around each triangle. The
|
||||
/// 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"]
|
||||
struct CustomMaterial {}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use bevy::{
|
||||
pbr::{MaterialPipeline, MaterialPipelineKey},
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::{
|
||||
mesh::{MeshVertexBufferLayout, PrimitiveTopology},
|
||||
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"]
|
||||
struct LineMaterial {
|
||||
#[uniform(0)]
|
||||
|
||||
@ -5,7 +5,7 @@ use bevy::{
|
||||
math::vec2,
|
||||
pbr::CascadeShadowConfigBuilder,
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::{
|
||||
render_resource::{
|
||||
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"]
|
||||
pub struct ColorGradientMaterial {}
|
||||
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
use bevy::{
|
||||
asset::{AssetLoader, LoadContext, LoadedAsset},
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
utils::BoxedFuture,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize, TypeUuid)]
|
||||
#[derive(Debug, Deserialize, TypeUuid, TypePath)]
|
||||
#[uuid = "39cadc56-aa9c-4543-8640-a018b74b5052"]
|
||||
pub struct CustomAsset {
|
||||
pub value: i32,
|
||||
|
||||
@ -3,14 +3,14 @@ use bevy::audio::AddAudioSource;
|
||||
use bevy::audio::AudioPlugin;
|
||||
use bevy::audio::Source;
|
||||
use bevy::prelude::*;
|
||||
use bevy::reflect::TypeUuid;
|
||||
use bevy::reflect::{TypePath, TypeUuid};
|
||||
use bevy::utils::Duration;
|
||||
|
||||
// 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.
|
||||
// Implementing `TypeUuid` will automatically implement `Asset`.
|
||||
// This allows the type to be registered as an asset.
|
||||
#[derive(TypeUuid)]
|
||||
#[derive(TypePath, TypeUuid)]
|
||||
#[uuid = "c2090c23-78fd-44f1-8508-c89b1f3cec29"]
|
||||
struct SineAudio {
|
||||
frequency: f32,
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
//! 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.
|
||||
|
||||
use bevy::{prelude::*, reflect::TypeUuid, render::render_resource::*};
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::render_resource::*,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
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"]
|
||||
struct CustomMaterial {}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use bevy::{
|
||||
asset::LoadState,
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
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"]
|
||||
struct ArrayTextureMaterial {
|
||||
#[texture(0, dimension = "2d_array")]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use bevy::{
|
||||
pbr::{MaterialPipeline, MaterialPipelineKey},
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::{
|
||||
mesh::{MeshVertexAttribute, MeshVertexBufferLayout},
|
||||
render_resource::{
|
||||
@ -57,7 +57,7 @@ fn setup(
|
||||
}
|
||||
|
||||
// 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"]
|
||||
pub struct CustomMaterial {
|
||||
#[uniform(0)]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use bevy::{
|
||||
pbr::{MaterialPipeline, MaterialPipelineKey},
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::{
|
||||
mesh::MeshVertexBufferLayout,
|
||||
render_resource::{
|
||||
@ -75,7 +75,7 @@ impl Material for CustomMaterial {
|
||||
}
|
||||
|
||||
// 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"]
|
||||
#[bind_group_data(CustomMaterialKey)]
|
||||
pub struct CustomMaterial {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::render_resource::{AsBindGroup, ShaderRef},
|
||||
};
|
||||
|
||||
@ -53,7 +53,7 @@ impl Material for CustomMaterial {
|
||||
}
|
||||
|
||||
// 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"]
|
||||
pub struct CustomMaterial {
|
||||
#[uniform(0)]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use bevy::{
|
||||
pbr::{MaterialPipeline, MaterialPipelineKey},
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::{
|
||||
mesh::MeshVertexBufferLayout,
|
||||
render_resource::{
|
||||
@ -47,7 +47,7 @@ fn setup(
|
||||
}
|
||||
|
||||
// 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"]
|
||||
pub struct CustomMaterial {
|
||||
#[uniform(0)]
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
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);
|
||||
}
|
||||
|
||||
#[derive(AsBindGroup, Debug, Clone, TypeUuid)]
|
||||
#[derive(AsBindGroup, Debug, Clone, TypeUuid, TypePath)]
|
||||
#[uuid = "b62bb455-a72c-4b56-87bb-81e0554e234f"]
|
||||
pub struct CustomMaterial {
|
||||
#[texture(0)]
|
||||
|
||||
@ -6,7 +6,7 @@ use bevy::{
|
||||
core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass, NormalPrepass},
|
||||
pbr::{NotShadowCaster, PbrPlugin},
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::render_resource::{AsBindGroup, ShaderRef, ShaderType},
|
||||
};
|
||||
|
||||
@ -155,7 +155,7 @@ fn setup(
|
||||
}
|
||||
|
||||
// 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"]
|
||||
pub struct CustomMaterial {
|
||||
#[uniform(0)]
|
||||
@ -204,7 +204,7 @@ struct ShowPrepassSettings {
|
||||
}
|
||||
|
||||
// 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"]
|
||||
pub struct PrepassOutputMaterial {
|
||||
#[uniform(0)]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
reflect::TypeUuid,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
render::{
|
||||
render_asset::RenderAssets,
|
||||
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"]
|
||||
struct BindlessMaterial {
|
||||
textures: Vec<Handle<Image>>,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user