reflect: implement the unique reflect rfc (#7207)

# Objective

- Implements the [Unique Reflect
RFC](https://github.com/nicopap/rfcs/blob/bevy-reflect-api/rfcs/56-better-reflect.md).

## Solution

- Implements the RFC.
- This implementation differs in some ways from the RFC:
- In the RFC, it was suggested `Reflect: Any` but `PartialReflect:
?Any`. During initial implementation I tried this, but we assume the
`PartialReflect: 'static` in a lot of places and the changes required
crept out of the scope of this PR.
- `PartialReflect::try_into_reflect` originally returned `Option<Box<dyn
Reflect>>` but i changed this to `Result<Box<dyn Reflect>, Box<dyn
PartialReflect>>` since the method takes by value and otherwise there
would be no way to recover the type. `as_full` and `as_full_mut` both
still return `Option<&(mut) dyn Reflect>`.

---

## Changelog

- Added `PartialReflect`.
- `Reflect` is now a subtrait of `PartialReflect`.
- Moved most methods on `Reflect` to the new `PartialReflect`.
- Added `PartialReflect::{as_partial_reflect, as_partial_reflect_mut,
into_partial_reflect}`.
- Added `PartialReflect::{try_as_reflect, try_as_reflect_mut,
try_into_reflect}`.
- Added `<dyn PartialReflect>::{try_downcast_ref, try_downcast_mut,
try_downcast, try_take}` supplementing the methods on `dyn Reflect`.

## Migration Guide

- Most instances of `dyn Reflect` should be changed to `dyn
PartialReflect` which is less restrictive, however trait bounds should
generally stay as `T: Reflect`.
- The new `PartialReflect::{as_partial_reflect, as_partial_reflect_mut,
into_partial_reflect, try_as_reflect, try_as_reflect_mut,
try_into_reflect}` methods as well as `Reflect::{as_reflect,
as_reflect_mut, into_reflect}` will need to be implemented for manual
implementors of `Reflect`.

## Future Work

- This PR is designed to be followed up by another "Unique Reflect Phase
2" that addresses the following points:
- Investigate making serialization revolve around `Reflect` instead of
`PartialReflect`.
- [Remove the `try_*` methods on `dyn PartialReflect` since they are
stop
gaps](https://github.com/bevyengine/bevy/pull/7207#discussion_r1083476050).
- Investigate usages like `ReflectComponent`. In the places they
currently use `PartialReflect`, should they be changed to use `Reflect`?
- Merging this opens the door to lots of reflection features we haven't
been able to implement.
- We could re-add [the `Reflectable`
trait](8e3488c880/crates/bevy_reflect/src/reflect.rs (L337-L342))
and make `FromReflect` a requirement to improve [`FromReflect`
ergonomics](https://github.com/bevyengine/rfcs/pull/59). This is
currently not possible because dynamic types cannot sensibly be
`FromReflect`.
  - Since this is an alternative to #5772, #5781 would be made cleaner.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
This commit is contained in:
radiish 2024-08-12 18:01:41 +01:00 committed by GitHub
parent 7b81ae7e40
commit 6ab8767d3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
65 changed files with 2271 additions and 1855 deletions

View file

@ -515,6 +515,8 @@ pub enum UntypedAssetConversionError {
#[cfg(test)]
mod tests {
use bevy_reflect::PartialReflect;
use super::*;
type TestAsset = ();
@ -651,7 +653,7 @@ mod tests {
);
let reflected: &dyn Reflect = &handle;
let cloned_handle: Box<dyn Reflect> = reflected.clone_value();
let cloned_handle: Box<dyn PartialReflect> = reflected.clone_value();
assert_eq!(
Arc::strong_count(strong),

View file

@ -1,7 +1,7 @@
use std::any::{Any, TypeId};
use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World};
use bevy_reflect::{FromReflect, FromType, Reflect};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect};
use crate::{Asset, AssetId, Assets, Handle, UntypedAssetId, UntypedHandle};
@ -22,8 +22,8 @@ pub struct ReflectAsset {
// - may only be called with an [`UnsafeWorldCell`] which can be used to access the corresponding `Assets<T>` resource mutably
// - may only be used to access **at most one** access at once
get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, UntypedHandle) -> Option<&mut dyn Reflect>,
add: fn(&mut World, &dyn Reflect) -> UntypedHandle,
insert: fn(&mut World, UntypedHandle, &dyn Reflect),
add: fn(&mut World, &dyn PartialReflect) -> UntypedHandle,
insert: fn(&mut World, UntypedHandle, &dyn PartialReflect),
len: fn(&World) -> usize,
ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = UntypedAssetId> + 'w>,
remove: fn(&mut World, UntypedHandle) -> Option<Box<dyn Reflect>>,
@ -94,11 +94,11 @@ impl ReflectAsset {
}
/// Equivalent of [`Assets::add`]
pub fn add(&self, world: &mut World, value: &dyn Reflect) -> UntypedHandle {
pub fn add(&self, world: &mut World, value: &dyn PartialReflect) -> UntypedHandle {
(self.add)(world, value)
}
/// Equivalent of [`Assets::insert`]
pub fn insert(&self, world: &mut World, handle: UntypedHandle, value: &dyn Reflect) {
pub fn insert(&self, world: &mut World, handle: UntypedHandle, value: &dyn PartialReflect) {
(self.insert)(world, handle, value);
}

View file

@ -4,13 +4,15 @@
//! This module exports two types: [`ReflectBundleFns`] and [`ReflectBundle`].
//!
//! Same as [`super::component`], but for bundles.
use std::any::TypeId;
use std::any::{Any, TypeId};
use crate::{
prelude::Bundle,
world::{EntityMut, EntityWorldMut},
};
use bevy_reflect::{FromReflect, FromType, Reflect, ReflectRef, TypeRegistry};
use bevy_reflect::{
FromReflect, FromType, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry,
};
use super::{from_reflect_with_fallback, ReflectComponent};
@ -27,11 +29,11 @@ pub struct ReflectBundle(ReflectBundleFns);
#[derive(Clone)]
pub struct ReflectBundleFns {
/// Function pointer implementing [`ReflectBundle::insert()`].
pub insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply()`].
pub apply: fn(EntityMut, &dyn Reflect, &TypeRegistry),
pub apply: fn(EntityMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::apply_or_insert()`].
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectBundle::remove()`].
pub remove: fn(&mut EntityWorldMut),
}
@ -42,7 +44,7 @@ impl ReflectBundleFns {
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Bundle + Reflect + FromReflect>() -> Self {
pub fn new<T: Bundle + FromReflect + TypePath>() -> Self {
<ReflectBundle as FromType<T>>::from_type().0
}
}
@ -52,7 +54,7 @@ impl ReflectBundle {
pub fn insert(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn Reflect,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, bundle, registry);
@ -66,7 +68,7 @@ impl ReflectBundle {
pub fn apply<'a>(
&self,
entity: impl Into<EntityMut<'a>>,
bundle: &dyn Reflect,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply)(entity.into(), bundle, registry);
@ -76,7 +78,7 @@ impl ReflectBundle {
pub fn apply_or_insert(
&self,
entity: &mut EntityWorldMut,
bundle: &dyn Reflect,
bundle: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(entity, bundle, registry);
@ -122,7 +124,7 @@ impl ReflectBundle {
}
}
impl<B: Bundle + Reflect> FromType<B> for ReflectBundle {
impl<B: Bundle + Reflect + TypePath> FromType<B> for ReflectBundle {
fn from_type() -> Self {
ReflectBundle(ReflectBundleFns {
insert: |entity, reflected_bundle, registry| {
@ -180,10 +182,16 @@ impl<B: Bundle + Reflect> FromType<B> for ReflectBundle {
}
}
fn apply_field(entity: &mut EntityMut, field: &dyn Reflect, registry: &TypeRegistry) {
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
fn apply_field(entity: &mut EntityMut, field: &dyn PartialReflect, registry: &TypeRegistry) {
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply(entity.reborrow(), field);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply(entity.reborrow(), field, registry);
} else {
panic!(
@ -195,19 +203,22 @@ fn apply_field(entity: &mut EntityMut, field: &dyn Reflect, registry: &TypeRegis
fn apply_or_insert_field(
entity: &mut EntityWorldMut,
field: &dyn Reflect,
field: &dyn PartialReflect,
registry: &TypeRegistry,
) {
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
panic!(
"`{}` did not implement `Reflect`",
field.reflect_type_path()
);
};
if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
reflect_component.apply_or_insert(entity, field, registry);
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
reflect_bundle.apply_or_insert(entity, field, registry);
} else {
let is_component = entity
.world()
.components()
.get_id(field.type_id())
.is_some();
let is_component = entity.world().components().get_id(type_id).is_some();
if is_component {
panic!(

View file

@ -67,7 +67,7 @@ use crate::{
FilteredEntityRef, World,
},
};
use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
/// A struct used to operate on reflected [`Component`] trait of a type.
///
@ -99,11 +99,11 @@ pub struct ReflectComponent(ReflectComponentFns);
#[derive(Clone)]
pub struct ReflectComponentFns {
/// Function pointer implementing [`ReflectComponent::insert()`].
pub insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::apply()`].
pub apply: fn(EntityMut, &dyn Reflect),
pub apply: fn(EntityMut, &dyn PartialReflect),
/// Function pointer implementing [`ReflectComponent::apply_or_insert()`].
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
pub apply_or_insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::remove()`].
pub remove: fn(&mut EntityWorldMut),
/// Function pointer implementing [`ReflectComponent::contains()`].
@ -127,7 +127,7 @@ impl ReflectComponentFns {
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Component + Reflect + FromReflect>() -> Self {
pub fn new<T: Component + FromReflect + TypePath>() -> Self {
<ReflectComponent as FromType<T>>::from_type().0
}
}
@ -137,7 +137,7 @@ impl ReflectComponent {
pub fn insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn Reflect,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(entity, component, registry);
@ -148,7 +148,7 @@ impl ReflectComponent {
/// # Panics
///
/// Panics if there is no [`Component`] of the given type.
pub fn apply<'a>(&self, entity: impl Into<EntityMut<'a>>, component: &dyn Reflect) {
pub fn apply<'a>(&self, entity: impl Into<EntityMut<'a>>, component: &dyn PartialReflect) {
(self.0.apply)(entity.into(), component);
}
@ -156,7 +156,7 @@ impl ReflectComponent {
pub fn apply_or_insert(
&self,
entity: &mut EntityWorldMut,
component: &dyn Reflect,
component: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(entity, component, registry);
@ -256,7 +256,7 @@ impl ReflectComponent {
}
}
impl<C: Component + Reflect> FromType<C> for ReflectComponent {
impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
fn from_type() -> Self {
ReflectComponent(ReflectComponentFns {
insert: |entity, reflected_component, registry| {
@ -271,7 +271,7 @@ impl<C: Component + Reflect> FromType<C> for ReflectComponent {
},
apply_or_insert: |entity, reflected_component, registry| {
if let Some(mut component) = entity.get_mut::<C>() {
component.apply(reflected_component);
component.apply(reflected_component.as_partial_reflect());
} else {
let component = entity.world_scope(|world| {
from_reflect_with_fallback::<C>(reflected_component, world, registry)

View file

@ -3,7 +3,7 @@ use crate::reflect::AppTypeRegistry;
use crate::system::{EntityCommands, Resource};
use crate::world::Command;
use crate::{entity::Entity, reflect::ReflectComponent, world::World};
use bevy_reflect::{Reflect, TypeRegistry};
use bevy_reflect::{PartialReflect, TypeRegistry};
use std::borrow::Cow;
use std::marker::PhantomData;
@ -18,7 +18,7 @@ pub trait ReflectCommandExt {
///
/// - If the entity doesn't exist.
/// - If [`AppTypeRegistry`] does not have the reflection data for the given [`Component`](crate::component::Component).
/// - If the component data is invalid. See [`Reflect::apply`] for further details.
/// - If the component data is invalid. See [`PartialReflect::apply`] for further details.
/// - If [`AppTypeRegistry`] is not present in the [`World`].
///
/// # Note
@ -69,7 +69,7 @@ pub trait ReflectCommandExt {
/// }
///
/// ```
fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self;
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self;
/// Same as [`insert_reflect`](ReflectCommandExt::insert_reflect), but using the `T` resource as type registry instead of
/// `AppTypeRegistry`.
@ -83,7 +83,7 @@ pub trait ReflectCommandExt {
/// - The given [`Resource`] is removed from the [`World`] before the command is applied.
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn Reflect>,
component: Box<dyn PartialReflect>,
) -> &mut Self;
/// Removes from the entity the component with the given type name registered in [`AppTypeRegistry`].
@ -142,7 +142,7 @@ pub trait ReflectCommandExt {
}
impl ReflectCommandExt for EntityCommands<'_> {
fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self {
fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
self.commands.add(InsertReflect {
entity: self.entity,
component,
@ -152,7 +152,7 @@ impl ReflectCommandExt for EntityCommands<'_> {
fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
&mut self,
component: Box<dyn Reflect>,
component: Box<dyn PartialReflect>,
) -> &mut Self {
self.commands.add(InsertReflectWithRegistry::<T> {
entity: self.entity,
@ -188,7 +188,7 @@ fn insert_reflect(
world: &mut World,
entity: Entity,
type_registry: &TypeRegistry,
component: Box<dyn Reflect>,
component: Box<dyn PartialReflect>,
) {
let type_info = component
.get_represented_type_info()
@ -197,13 +197,13 @@ fn insert_reflect(
let Some(mut entity) = world.get_entity_mut(entity) else {
panic!("error[B0003]: Could not insert a reflected component (of type {type_path}) for entity {entity:?} because it doesn't exist in this World. See: https://bevyengine.org/learn/errors/b0003");
};
let Some(type_registration) = type_registry.get_with_type_path(type_path) else {
let Some(type_registration) = type_registry.get(type_info.type_id()) else {
panic!("Could not get type registration (for component type {type_path}) because it doesn't exist in the TypeRegistry.");
};
let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
panic!("Could not get ReflectComponent data (for component type {type_path}) because it doesn't exist in this TypeRegistration.");
};
reflect_component.insert(&mut entity, &*component, type_registry);
reflect_component.insert(&mut entity, component.as_partial_reflect(), type_registry);
}
/// A [`Command`] that adds the boxed reflect component to an entity using the data in
@ -214,7 +214,7 @@ pub struct InsertReflect {
/// The entity on which the component will be inserted.
pub entity: Entity,
/// The reflect [`Component`](crate::component::Component) that will be added to the entity.
pub component: Box<dyn Reflect>,
pub component: Box<dyn PartialReflect>,
}
impl Command for InsertReflect {
@ -233,7 +233,7 @@ pub struct InsertReflectWithRegistry<T: Resource + AsRef<TypeRegistry>> {
pub entity: Entity,
pub _t: PhantomData<T>,
/// The reflect [`Component`](crate::component::Component) that will be added to the entity.
pub component: Box<dyn Reflect>,
pub component: Box<dyn PartialReflect>,
}
impl<T: Resource + AsRef<TypeRegistry>> Command for InsertReflectWithRegistry<T> {
@ -317,7 +317,7 @@ mod tests {
use crate::system::{Commands, SystemState};
use crate::{self as bevy_ecs, component::Component, world::World};
use bevy_ecs_macros::Resource;
use bevy_reflect::{Reflect, TypeRegistry};
use bevy_reflect::{PartialReflect, Reflect, TypeRegistry};
#[derive(Resource)]
struct TypeRegistryResource {
@ -352,7 +352,7 @@ mod tests {
let entity = commands.spawn_empty().id();
let entity2 = commands.spawn_empty().id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
let boxed_reflect_component_a_clone = boxed_reflect_component_a.clone_value();
commands
@ -388,7 +388,7 @@ mod tests {
let entity = commands.spawn_empty().id();
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
commands
.entity(entity)

View file

@ -6,7 +6,9 @@ use std::ops::{Deref, DerefMut};
use crate as bevy_ecs;
use crate::{system::Resource, world::World};
use bevy_reflect::std_traits::ReflectDefault;
use bevy_reflect::{Reflect, ReflectFromReflect, TypeRegistry, TypeRegistryArc};
use bevy_reflect::{
PartialReflect, Reflect, ReflectFromReflect, TypePath, TypeRegistry, TypeRegistryArc,
};
mod bundle;
mod component;
@ -69,7 +71,7 @@ impl DerefMut for AppFunctionRegistry {
}
}
/// Creates a `T` from a `&dyn Reflect`.
/// Creates a `T` from a `&dyn PartialReflect`.
///
/// This will try the following strategies, in this order:
///
@ -85,18 +87,17 @@ impl DerefMut for AppFunctionRegistry {
/// this method will panic.
///
/// If none of the strategies succeed, this method will panic.
pub fn from_reflect_with_fallback<T: Reflect>(
reflected: &dyn Reflect,
pub fn from_reflect_with_fallback<T: Reflect + TypePath>(
reflected: &dyn PartialReflect,
world: &mut World,
registry: &TypeRegistry,
) -> T {
fn different_type_error<T>(reflected: &str) -> ! {
fn different_type_error<T: TypePath>(reflected: &str) -> ! {
panic!(
"The registration for the reflected `{}` trait for the type `{}` produced \
a value of a different type",
reflected,
// FIXME: once we have unique reflect, use `TypePath`.
std::any::type_name::<T>(),
T::type_path(),
);
}

View file

@ -9,7 +9,7 @@ use crate::{
system::Resource,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
use super::from_reflect_with_fallback;
@ -43,11 +43,11 @@ pub struct ReflectResource(ReflectResourceFns);
#[derive(Clone)]
pub struct ReflectResourceFns {
/// Function pointer implementing [`ReflectResource::insert()`].
pub insert: fn(&mut World, &dyn Reflect, &TypeRegistry),
pub insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::apply()`].
pub apply: fn(&mut World, &dyn Reflect),
pub apply: fn(&mut World, &dyn PartialReflect),
/// Function pointer implementing [`ReflectResource::apply_or_insert()`].
pub apply_or_insert: fn(&mut World, &dyn Reflect, &TypeRegistry),
pub apply_or_insert: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::remove()`].
pub remove: fn(&mut World),
/// Function pointer implementing [`ReflectResource::reflect()`].
@ -67,14 +67,19 @@ impl ReflectResourceFns {
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: Resource + FromReflect>() -> Self {
pub fn new<T: Resource + FromReflect + TypePath>() -> Self {
<ReflectResource as FromType<T>>::from_type().0
}
}
impl ReflectResource {
/// Insert a reflected [`Resource`] into the world like [`insert()`](World::insert_resource).
pub fn insert(&self, world: &mut World, resource: &dyn Reflect, registry: &TypeRegistry) {
pub fn insert(
&self,
world: &mut World,
resource: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.insert)(world, resource, registry);
}
@ -83,7 +88,7 @@ impl ReflectResource {
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn apply(&self, world: &mut World, resource: &dyn Reflect) {
pub fn apply(&self, world: &mut World, resource: &dyn PartialReflect) {
(self.0.apply)(world, resource);
}
@ -91,7 +96,7 @@ impl ReflectResource {
pub fn apply_or_insert(
&self,
world: &mut World,
resource: &dyn Reflect,
resource: &dyn PartialReflect,
registry: &TypeRegistry,
) {
(self.0.apply_or_insert)(world, resource, registry);
@ -176,7 +181,7 @@ impl ReflectResource {
}
}
impl<R: Resource + Reflect> FromType<R> for ReflectResource {
impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
fn from_type() -> Self {
ReflectResource(ReflectResourceFns {
insert: |world, reflected_resource, registry| {

View file

@ -8,7 +8,7 @@
This crate enables you to dynamically interact with Rust types:
* Derive the Reflect traits
* Derive the `Reflect` traits
* Interact with fields using their names (for named structs) or indices (for tuple structs)
* "Patch" your types with new values
* Look up nested fields using "path strings"
@ -18,10 +18,10 @@ This crate enables you to dynamically interact with Rust types:
## Features
### Derive the Reflect traits
### Derive the `Reflect` traits
```rust ignore
// this will automatically implement the Reflect trait and the Struct trait (because the type is a struct)
// this will automatically implement the `Reflect` trait and the `Struct` trait (because the type is a struct)
#[derive(Reflect)]
struct Foo {
a: u32,
@ -30,7 +30,7 @@ struct Foo {
d: Vec<Baz>,
}
// this will automatically implement the Reflect trait and the TupleStruct trait (because the type is a tuple struct)
// this will automatically implement the `Reflect` trait and the `TupleStruct` trait (because the type is a tuple struct)
#[derive(Reflect)]
struct Bar(String);

View file

@ -17,5 +17,5 @@ fn main() {
// foo doesn't implement Reflect because NoReflect doesn't implement Reflect
foo.get_field::<NoReflect>("a").unwrap();
//~^ ERROR: `NoReflect` can not be reflected
//~^ ERROR: `NoReflect` does not implement `Reflect` so cannot be fully reflected
}

View file

@ -444,7 +444,7 @@ impl ContainerAttributes {
&self.type_path_attrs
}
/// Returns the implementation of `Reflect::reflect_hash` as a `TokenStream`.
/// Returns the implementation of `PartialReflect::reflect_hash` as a `TokenStream`.
///
/// If `Hash` was not registered, returns `None`.
pub fn get_hash_impl(&self, bevy_reflect_path: &Path) -> Option<proc_macro2::TokenStream> {
@ -467,7 +467,7 @@ impl ContainerAttributes {
}
}
/// Returns the implementation of `Reflect::reflect_partial_eq` as a `TokenStream`.
/// Returns the implementation of `PartialReflect::reflect_partial_eq` as a `TokenStream`.
///
/// If `PartialEq` was not registered, returns `None`.
pub fn get_partial_eq_impl(
@ -476,9 +476,9 @@ impl ContainerAttributes {
) -> Option<proc_macro2::TokenStream> {
match &self.partial_eq {
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<bool> {
let value = <dyn #bevy_reflect_path::Reflect>::as_any(value);
if let #FQOption::Some(value) = <dyn #FQAny>::downcast_ref::<Self>(value) {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {
let value = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<Self>(value);
if let #FQOption::Some(value) = value {
#FQOption::Some(::core::cmp::PartialEq::eq(self, value))
} else {
#FQOption::Some(false)
@ -486,7 +486,7 @@ impl ContainerAttributes {
}
}),
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<bool> {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {
#FQOption::Some(#impl_fn(self, value))
}
}),
@ -494,7 +494,7 @@ impl ContainerAttributes {
}
}
/// Returns the implementation of `Reflect::debug` as a `TokenStream`.
/// Returns the implementation of `PartialReflect::debug` as a `TokenStream`.
///
/// If `Debug` was not registered, returns `None`.
pub fn get_debug_impl(&self) -> Option<proc_macro2::TokenStream> {

View file

@ -209,7 +209,7 @@ impl<'a> VariantBuilder for FromReflectVariantBuilder<'a> {
}
}
/// Generates the enum variant output data needed to build the `Reflect::try_apply` implementation.
/// Generates the enum variant output data needed to build the `PartialReflect::try_apply` implementation.
pub(crate) struct TryApplyVariantBuilder<'a> {
reflect_enum: &'a ReflectEnum<'a>,
}

View file

@ -4,7 +4,7 @@ use crate::enum_utility::{EnumVariantOutputData, FromReflectVariantBuilder, Vari
use crate::field_attributes::DefaultBehavior;
use crate::utility::{ident_or_index, WhereClauseOptions};
use crate::{ReflectMeta, ReflectStruct};
use bevy_macro_utils::fq_std::{FQAny, FQClone, FQDefault, FQOption};
use bevy_macro_utils::fq_std::{FQClone, FQDefault, FQOption};
use proc_macro2::Span;
use quote::{quote, ToTokens};
use syn::{Field, Ident, Lit, LitInt, LitStr, Member};
@ -26,8 +26,12 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
let where_from_reflect_clause = WhereClauseOptions::new(meta).extend_where_clause(where_clause);
quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #type_path #ty_generics #where_from_reflect_clause {
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #FQOption<Self> {
#FQOption::Some(#FQClone::clone(<dyn #FQAny>::downcast_ref::<#type_path #ty_generics>(<dyn #bevy_reflect_path::Reflect>::as_any(reflect))?))
fn from_reflect(reflect: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<Self> {
#FQOption::Some(
#FQClone::clone(
<dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<#type_path #ty_generics>(reflect)?
)
)
}
}
}
@ -57,8 +61,10 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
quote! {
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) {
fn from_reflect(#ref_value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<Self> {
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) =
#bevy_reflect_path::PartialReflect::reflect_ref(#ref_value)
{
match #bevy_reflect_path::Enum::variant_name(#ref_value) {
#(#variant_names => #fqoption::Some(#variant_constructors),)*
name => panic!("variant with name `{}` does not exist on enum `{}`", name, <Self as #bevy_reflect_path::TypePath>::type_path()),
@ -138,8 +144,10 @@ fn impl_struct_internal(
quote! {
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) {
fn from_reflect(reflect: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<Self> {
if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct)
= #bevy_reflect_path::PartialReflect::reflect_ref(reflect)
{
#constructor
} else {
#FQOption::None

View file

@ -0,0 +1,135 @@
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQOption, FQResult};
use quote::quote;
use crate::{derive_data::ReflectMeta, utility::WhereClauseOptions};
pub fn impl_full_reflect(
meta: &ReflectMeta,
where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path();
let type_path = meta.type_path();
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
quote! {
impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self
}
#[inline]
fn as_any(&self) -> &dyn #FQAny {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
self
}
#[inline]
fn into_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn set(
&mut self,
value: #FQBox<dyn #bevy_reflect_path::Reflect>
) -> #FQResult<(), #FQBox<dyn #bevy_reflect_path::Reflect>> {
*self = <dyn #bevy_reflect_path::Reflect>::take(value)?;
#FQResult::Ok(())
}
}
}
}
pub fn common_partial_reflect_methods(
meta: &ReflectMeta,
default_partial_eq_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,
default_hash_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,
) -> proc_macro2::TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path();
let debug_fn = meta.attrs().get_debug_impl();
let partial_eq_fn = meta
.attrs()
.get_partial_eq_impl(bevy_reflect_path)
.or_else(move || {
let default_delegate = default_partial_eq_delegate();
default_delegate.map(|func| {
quote! {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {
(#func)(self, value)
}
}
})
});
let hash_fn = meta
.attrs()
.get_hash_impl(bevy_reflect_path)
.or_else(move || {
let default_delegate = default_hash_delegate();
default_delegate.map(|func| {
quote! {
fn reflect_hash(&self) -> #FQOption<u64> {
(#func)(self)
}
}
})
});
quote! {
#[inline]
fn try_into_reflect(
self: #FQBox<Self>
) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #FQBox<dyn #bevy_reflect_path::PartialReflect>> {
#FQResult::Ok(self)
}
#[inline]
fn try_as_reflect(&self) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
#FQOption::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
#FQOption::Some(self)
}
#[inline]
fn into_partial_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn #bevy_reflect_path::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::PartialReflect {
self
}
#hash_fn
#partial_eq_fn
#debug_fn
}
}

View file

@ -1,7 +1,7 @@
use crate::derive_data::{EnumVariantFields, ReflectEnum, StructField};
use crate::enum_utility::{EnumVariantOutputData, TryApplyVariantBuilder, VariantBuilder};
use crate::impls::{impl_type_path, impl_typed};
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQOption, FQResult};
use crate::impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed};
use bevy_macro_utils::fq_std::{FQBox, FQOption, FQResult};
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::Fields;
@ -33,30 +33,6 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
..
} = TryApplyVariantBuilder::new(reflect_enum).build(&ref_value);
let hash_fn = reflect_enum
.meta()
.attrs()
.get_hash_impl(bevy_reflect_path)
.unwrap_or_else(|| {
quote! {
fn reflect_hash(&self) -> #FQOption<u64> {
#bevy_reflect_path::enum_hash(self)
}
}
});
let debug_fn = reflect_enum.meta().attrs().get_debug_impl();
let partial_eq_fn = reflect_enum
.meta()
.attrs()
.get_partial_eq_impl(bevy_reflect_path)
.unwrap_or_else(|| {
quote! {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<bool> {
#bevy_reflect_path::enum_partial_eq(self, value)
}
}
});
let typed_impl = impl_typed(
reflect_enum.meta(),
&where_clause_options,
@ -64,6 +40,12 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
);
let type_path_impl = impl_type_path(reflect_enum.meta());
let full_reflect_impl = impl_full_reflect(reflect_enum.meta(), &where_clause_options);
let common_methods = common_partial_reflect_methods(
reflect_enum.meta(),
|| Some(quote!(#bevy_reflect_path::enum_partial_eq)),
|| Some(quote!(#bevy_reflect_path::enum_hash)),
);
#[cfg(not(feature = "functions"))]
let function_impls = None::<proc_macro2::TokenStream>;
@ -85,31 +67,33 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
#type_path_impl
#full_reflect_impl
#function_impls
impl #impl_generics #bevy_reflect_path::Enum for #enum_path #ty_generics #where_reflect_clause {
fn field(&self, #ref_name: &str) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
fn field(&self, #ref_name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match self {
#(#enum_field,)*
_ => #FQOption::None,
}
}
fn field_at(&self, #ref_index: usize) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
fn field_at(&self, #ref_index: usize) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match self {
#(#enum_field_at,)*
_ => #FQOption::None,
}
}
fn field_mut(&mut self, #ref_name: &str) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
fn field_mut(&mut self, #ref_name: &str) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
match self {
#(#enum_field,)*
_ => #FQOption::None,
}
}
fn field_at_mut(&mut self, #ref_index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
fn field_at_mut(&mut self, #ref_index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
match self {
#(#enum_field_at,)*
_ => #FQOption::None,
@ -171,56 +155,24 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
}
}
impl #impl_generics #bevy_reflect_path::Reflect for #enum_path #ty_generics #where_reflect_clause {
impl #impl_generics #bevy_reflect_path::PartialReflect for #enum_path #ty_generics #where_reflect_clause {
#[inline]
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
}
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self
}
#[inline]
fn as_any(&self) -> &dyn #FQAny {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
self
}
#[inline]
fn into_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#bevy_reflect_path::Enum::clone_dynamic(self))
}
#[inline]
fn set(&mut self, #ref_value: #FQBox<dyn #bevy_reflect_path::Reflect>) -> #FQResult<(), #FQBox<dyn #bevy_reflect_path::Reflect>> {
*self = <dyn #bevy_reflect_path::Reflect>::take(#ref_value)?;
#FQResult::Ok(())
}
#[inline]
fn try_apply(&mut self, #ref_value: &dyn #bevy_reflect_path::Reflect) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) {
fn try_apply(
&mut self,
#ref_value: &dyn #bevy_reflect_path::PartialReflect
) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) =
#bevy_reflect_path::PartialReflect::reflect_ref(#ref_value) {
if #bevy_reflect_path::Enum::variant_name(self) == #bevy_reflect_path::Enum::variant_name(#ref_value) {
// Same variant -> just update fields
match #bevy_reflect_path::Enum::variant_type(#ref_value) {
@ -228,14 +180,14 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
for field in #bevy_reflect_path::Enum::iter_fields(#ref_value) {
let name = field.name().unwrap();
if let #FQOption::Some(v) = #bevy_reflect_path::Enum::field_mut(self, name) {
#bevy_reflect_path::Reflect::try_apply(v, field.value())?;
#bevy_reflect_path::PartialReflect::try_apply(v, field.value())?;
}
}
}
#bevy_reflect_path::VariantType::Tuple => {
for (index, field) in ::core::iter::Iterator::enumerate(#bevy_reflect_path::Enum::iter_fields(#ref_value)) {
if let #FQOption::Some(v) = #bevy_reflect_path::Enum::field_at_mut(self, index) {
#bevy_reflect_path::Reflect::try_apply(v, field.value())?;
#bevy_reflect_path::PartialReflect::try_apply(v, field.value())?;
}
}
}
@ -260,7 +212,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
} else {
return #FQResult::Err(
#bevy_reflect_path::ApplyError::MismatchedKinds {
from_kind: #bevy_reflect_path::Reflect::reflect_kind(#ref_value),
from_kind: #bevy_reflect_path::PartialReflect::reflect_kind(#ref_value),
to_kind: #bevy_reflect_path::ReflectKind::Enum,
}
);
@ -284,11 +236,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
#bevy_reflect_path::ReflectOwned::Enum(self)
}
#hash_fn
#partial_eq_fn
#debug_fn
#common_methods
}
}
}

View file

@ -1,3 +1,4 @@
mod common;
mod enums;
#[cfg(feature = "functions")]
mod func;
@ -6,6 +7,7 @@ mod tuple_structs;
mod typed;
mod values;
pub(crate) use common::{common_partial_reflect_methods, impl_full_reflect};
pub(crate) use enums::impl_enum;
#[cfg(feature = "functions")]
pub(crate) use func::impl_function_traits;

View file

@ -1,7 +1,7 @@
use crate::impls::{impl_type_path, impl_typed};
use crate::impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed};
use crate::utility::ident_or_index;
use crate::ReflectStruct;
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQBox, FQDefault, FQOption, FQResult};
use quote::{quote, ToTokens};
/// Implements `Struct`, `GetTypeRegistration`, and `Reflect` for the given derive data.
@ -29,22 +29,6 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
let field_count = field_idents.len();
let field_indices = (0..field_count).collect::<Vec<usize>>();
let hash_fn = reflect_struct
.meta()
.attrs()
.get_hash_impl(bevy_reflect_path);
let debug_fn = reflect_struct.meta().attrs().get_debug_impl();
let partial_eq_fn = reflect_struct.meta()
.attrs()
.get_partial_eq_impl(bevy_reflect_path)
.unwrap_or_else(|| {
quote! {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<bool> {
#bevy_reflect_path::struct_partial_eq(self, value)
}
}
});
let where_clause_options = reflect_struct.where_clause_options();
let typed_impl = impl_typed(
reflect_struct.meta(),
@ -53,6 +37,12 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
);
let type_path_impl = impl_type_path(reflect_struct.meta());
let full_reflect_impl = impl_full_reflect(reflect_struct.meta(), &where_clause_options);
let common_methods = common_partial_reflect_methods(
reflect_struct.meta(),
|| Some(quote!(#bevy_reflect_path::struct_partial_eq)),
|| None,
);
#[cfg(not(feature = "functions"))]
let function_impls = None::<proc_macro2::TokenStream>;
@ -77,31 +67,33 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
#type_path_impl
#full_reflect_impl
#function_impls
impl #impl_generics #bevy_reflect_path::Struct for #struct_path #ty_generics #where_reflect_clause {
fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match name {
#(#field_names => #fqoption::Some(&self.#field_idents),)*
_ => #FQOption::None,
}
}
fn field_mut(&mut self, name: &str) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
fn field_mut(&mut self, name: &str) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
match name {
#(#field_names => #fqoption::Some(&mut self.#field_idents),)*
_ => #FQOption::None,
}
}
fn field_at(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
fn field_at(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match index {
#(#field_indices => #fqoption::Some(&self.#field_idents),)*
_ => #FQOption::None,
}
}
fn field_at_mut(&mut self, index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
fn field_at_mut(&mut self, index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
match index {
#(#field_indices => #fqoption::Some(&mut self.#field_idents),)*
_ => #FQOption::None,
@ -125,72 +117,40 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicStruct {
let mut dynamic: #bevy_reflect_path::DynamicStruct = #FQDefault::default();
dynamic.set_represented_type(#bevy_reflect_path::Reflect::get_represented_type_info(self));
#(dynamic.insert_boxed(#field_names, #bevy_reflect_path::Reflect::clone_value(&self.#field_idents));)*
dynamic.set_represented_type(#bevy_reflect_path::PartialReflect::get_represented_type_info(self));
#(dynamic.insert_boxed(#field_names, #bevy_reflect_path::PartialReflect::clone_value(&self.#field_idents));)*
dynamic
}
}
impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
impl #impl_generics #bevy_reflect_path::PartialReflect for #struct_path #ty_generics #where_reflect_clause {
#[inline]
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
}
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self
}
#[inline]
fn as_any(&self) -> &dyn #FQAny {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
self
}
#[inline]
fn into_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#bevy_reflect_path::Struct::clone_dynamic(self))
}
#[inline]
fn set(&mut self, value: #FQBox<dyn #bevy_reflect_path::Reflect>) -> #FQResult<(), #FQBox<dyn #bevy_reflect_path::Reflect>> {
*self = <dyn #bevy_reflect_path::Reflect>::take(value)?;
#FQResult::Ok(())
}
#[inline]
fn try_apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #bevy_reflect_path::ReflectRef::Struct(struct_value) = #bevy_reflect_path::Reflect::reflect_ref(value) {
fn try_apply(
&mut self,
value: &dyn #bevy_reflect_path::PartialReflect
) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #bevy_reflect_path::ReflectRef::Struct(struct_value)
= #bevy_reflect_path::PartialReflect::reflect_ref(value) {
for (i, value) in ::core::iter::Iterator::enumerate(#bevy_reflect_path::Struct::iter_fields(struct_value)) {
let name = #bevy_reflect_path::Struct::name_at(struct_value, i).unwrap();
if let #FQOption::Some(v) = #bevy_reflect_path::Struct::field_mut(self, name) {
#bevy_reflect_path::Reflect::try_apply(v, value)?;
#bevy_reflect_path::PartialReflect::try_apply(v, value)?;
}
}
} else {
return #FQResult::Err(
#bevy_reflect_path::ApplyError::MismatchedKinds {
from_kind: #bevy_reflect_path::Reflect::reflect_kind(value),
from_kind: #bevy_reflect_path::PartialReflect::reflect_kind(value),
to_kind: #bevy_reflect_path::ReflectKind::Struct
}
);
@ -214,11 +174,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
#bevy_reflect_path::ReflectOwned::Struct(self)
}
#hash_fn
#partial_eq_fn
#debug_fn
#common_methods
}
}
}

View file

@ -1,6 +1,6 @@
use crate::impls::{impl_type_path, impl_typed};
use crate::impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed};
use crate::ReflectStruct;
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQBox, FQDefault, FQOption, FQResult};
use quote::{quote, ToTokens};
use syn::{Index, Member};
@ -21,23 +21,6 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
let where_clause_options = reflect_struct.where_clause_options();
let get_type_registration_impl = reflect_struct.get_type_registration(&where_clause_options);
let hash_fn = reflect_struct
.meta()
.attrs()
.get_hash_impl(bevy_reflect_path);
let debug_fn = reflect_struct.meta().attrs().get_debug_impl();
let partial_eq_fn = reflect_struct
.meta()
.attrs()
.get_partial_eq_impl(bevy_reflect_path)
.unwrap_or_else(|| {
quote! {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #FQOption<bool> {
#bevy_reflect_path::tuple_struct_partial_eq(self, value)
}
}
});
let typed_impl = impl_typed(
reflect_struct.meta(),
&where_clause_options,
@ -45,6 +28,12 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
);
let type_path_impl = impl_type_path(reflect_struct.meta());
let full_reflect_impl = impl_full_reflect(reflect_struct.meta(), &where_clause_options);
let common_methods = common_partial_reflect_methods(
reflect_struct.meta(),
|| Some(quote!(#bevy_reflect_path::tuple_struct_partial_eq)),
|| None,
);
#[cfg(not(feature = "functions"))]
let function_impls = None::<proc_macro2::TokenStream>;
@ -67,17 +56,19 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
#type_path_impl
#full_reflect_impl
#function_impls
impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_path #ty_generics #where_reflect_clause {
fn field(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
fn field(&self, index: usize) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> {
match index {
#(#field_indices => #fqoption::Some(&self.#field_idents),)*
_ => #FQOption::None,
}
}
fn field_mut(&mut self, index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
fn field_mut(&mut self, index: usize) -> #FQOption<&mut dyn #bevy_reflect_path::PartialReflect> {
match index {
#(#field_indices => #fqoption::Some(&mut self.#field_idents),)*
_ => #FQOption::None,
@ -94,71 +85,38 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicTupleStruct {
let mut dynamic: #bevy_reflect_path::DynamicTupleStruct = #FQDefault::default();
dynamic.set_represented_type(#bevy_reflect_path::Reflect::get_represented_type_info(self));
#(dynamic.insert_boxed(#bevy_reflect_path::Reflect::clone_value(&self.#field_idents));)*
dynamic.set_represented_type(#bevy_reflect_path::PartialReflect::get_represented_type_info(self));
#(dynamic.insert_boxed(#bevy_reflect_path::PartialReflect::clone_value(&self.#field_idents));)*
dynamic
}
}
impl #impl_generics #bevy_reflect_path::Reflect for #struct_path #ty_generics #where_reflect_clause {
impl #impl_generics #bevy_reflect_path::PartialReflect for #struct_path #ty_generics #where_reflect_clause {
#[inline]
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
}
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self
}
#[inline]
fn as_any(&self) -> &dyn #FQAny {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
self
}
#[inline]
fn into_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#bevy_reflect_path::TupleStruct::clone_dynamic(self))
}
#[inline]
fn set(&mut self, value: #FQBox<dyn #bevy_reflect_path::Reflect>) -> #FQResult<(), #FQBox<dyn #bevy_reflect_path::Reflect>> {
*self = <dyn #bevy_reflect_path::Reflect>::take(value)?;
#FQResult::Ok(())
}
#[inline]
fn try_apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #bevy_reflect_path::ReflectRef::TupleStruct(struct_value) = #bevy_reflect_path::Reflect::reflect_ref(value) {
fn try_apply(
&mut self,
value: &dyn #bevy_reflect_path::PartialReflect
) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #bevy_reflect_path::ReflectRef::TupleStruct(struct_value) =
#bevy_reflect_path::PartialReflect::reflect_ref(value) {
for (i, value) in ::core::iter::Iterator::enumerate(#bevy_reflect_path::TupleStruct::iter_fields(struct_value)) {
if let #FQOption::Some(v) = #bevy_reflect_path::TupleStruct::field_mut(self, i) {
#bevy_reflect_path::Reflect::try_apply(v, value)?;
#bevy_reflect_path::PartialReflect::try_apply(v, value)?;
}
}
} else {
return #FQResult::Err(
#bevy_reflect_path::ApplyError::MismatchedKinds {
from_kind: #bevy_reflect_path::Reflect::reflect_kind(value),
from_kind: #bevy_reflect_path::PartialReflect::reflect_kind(value),
to_kind: #bevy_reflect_path::ReflectKind::TupleStruct,
}
);
@ -182,11 +140,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
#bevy_reflect_path::ReflectOwned::TupleStruct(self)
}
#hash_fn
#partial_eq_fn
#debug_fn
#common_methods
}
}
}

View file

@ -1,7 +1,7 @@
use crate::impls::{impl_type_path, impl_typed};
use crate::impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed};
use crate::utility::WhereClauseOptions;
use crate::ReflectMeta;
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQBox, FQClone, FQOption, FQResult};
use quote::quote;
/// Implements `GetTypeRegistration` and `Reflect` for the given type data.
@ -9,10 +9,6 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path();
let type_path = meta.type_path();
let hash_fn = meta.attrs().get_hash_impl(bevy_reflect_path);
let partial_eq_fn = meta.attrs().get_partial_eq_impl(bevy_reflect_path);
let debug_fn = meta.attrs().get_debug_impl();
#[cfg(feature = "documentation")]
let with_docs = {
let doc = quote::ToTokens::to_token_stream(meta.doc());
@ -32,6 +28,8 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
);
let type_path_impl = impl_type_path(meta);
let full_reflect_impl = impl_full_reflect(meta, &where_clause_options);
let common_methods = common_partial_reflect_methods(meta, || None, || None);
#[cfg(not(feature = "functions"))]
let function_impls = None::<proc_macro2::TokenStream>;
@ -49,53 +47,27 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
#typed_impl
#full_reflect_impl
#function_impls
impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {
impl #impl_generics #bevy_reflect_path::PartialReflect for #type_path #ty_generics #where_reflect_clause {
#[inline]
fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> {
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
}
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
self
}
#[inline]
fn as_any(&self) -> &dyn #FQAny {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
self
}
#[inline]
fn into_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#FQClone::clone(self))
}
#[inline]
fn try_apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
let any = #bevy_reflect_path::Reflect::as_any(value);
if let #FQOption::Some(value) = <dyn #FQAny>::downcast_ref::<Self>(any) {
fn try_apply(
&mut self,
value: &dyn #bevy_reflect_path::PartialReflect
) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
if let #FQOption::Some(value) = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<Self>(value) {
*self = #FQClone::clone(value);
} else {
return #FQResult::Err(
@ -108,12 +80,6 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
#FQResult::Ok(())
}
#[inline]
fn set(&mut self, value: #FQBox<dyn #bevy_reflect_path::Reflect>) -> #FQResult<(), #FQBox<dyn #bevy_reflect_path::Reflect>> {
*self = <dyn #bevy_reflect_path::Reflect>::take(value)?;
#FQResult::Ok(())
}
#[inline]
fn reflect_kind(&self) -> #bevy_reflect_path::ReflectKind {
#bevy_reflect_path::ReflectKind::Value
@ -134,11 +100,7 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
#bevy_reflect_path::ReflectOwned::Value(self)
}
#hash_fn
#partial_eq_fn
#debug_fn
#common_methods
}
}
}

View file

@ -94,7 +94,7 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {
/// The default bounds added are as follows:
/// - `Self` has the bounds `Any + Send + Sync`
/// - Type parameters have the bound `TypePath` unless `#[reflect(type_path = false)]` is present
/// - Active fields have the bounds `TypePath` and either `Reflect` if `#[reflect(from_reflect = false)]` is present
/// - Active fields have the bounds `TypePath` and either `PartialReflect` if `#[reflect(from_reflect = false)]` is present
/// or `FromReflect` otherwise (or no bounds at all if `#[reflect(no_field_bounds)]` is present)
///
/// When the derive is used with `#[reflect(where)]`, the bounds specified in the attribute are added as well.
@ -236,14 +236,14 @@ impl<'a, 'b> WhereClauseOptions<'a, 'b> {
}
}
/// The `Reflect` or `FromReflect` bound to use based on `#[reflect(from_reflect = false)]`.
/// The `PartialReflect` or `FromReflect` bound to use based on `#[reflect(from_reflect = false)]`.
fn reflect_bound(&self) -> TokenStream {
let bevy_reflect_path = self.meta.bevy_reflect_path();
if self.meta.from_reflect().should_auto_derive() {
quote!(#bevy_reflect_path::FromReflect)
} else {
quote!(#bevy_reflect_path::Reflect)
quote!(#bevy_reflect_path::PartialReflect)
}
}

View file

@ -1,6 +1,6 @@
use crate::{
self as bevy_reflect, utility::reflect_hasher, ApplyError, MaybeTyped, Reflect, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
self as bevy_reflect, utility::reflect_hasher, ApplyError, MaybeTyped, PartialReflect, Reflect,
ReflectKind, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
};
use bevy_reflect_derive::impl_type_path;
use std::{
@ -28,13 +28,13 @@ use std::{
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, Array};
/// use bevy_reflect::{PartialReflect, Array};
///
/// let foo: &dyn Array = &[123_u32, 456_u32, 789_u32];
/// assert_eq!(foo.len(), 3);
///
/// let field: &dyn Reflect = foo.get(0).unwrap();
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
/// let field: &dyn PartialReflect = foo.get(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
@ -44,12 +44,12 @@ use std::{
/// [`GetTypeRegistration`]: crate::GetTypeRegistration
/// [limitation]: https://github.com/serde-rs/serde/issues/1937
/// [`Deserialize`]: ::serde::Deserialize
pub trait Array: Reflect {
pub trait Array: PartialReflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn Reflect>;
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of elements in the array.
fn len(&self) -> usize;
@ -63,13 +63,13 @@ pub trait Array: Reflect {
fn iter(&self) -> ArrayIter;
/// Drain the elements of this array to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>>;
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the list, producing a [`DynamicArray`].
fn clone_dynamic(&self) -> DynamicArray {
DynamicArray {
represented_type: self.get_represented_type_info(),
values: self.iter().map(Reflect::clone_value).collect(),
values: self.iter().map(PartialReflect::clone_value).collect(),
}
}
}
@ -191,12 +191,12 @@ impl ArrayInfo {
#[derive(Debug)]
pub struct DynamicArray {
pub(crate) represented_type: Option<&'static TypeInfo>,
pub(crate) values: Box<[Box<dyn Reflect>]>,
pub(crate) values: Box<[Box<dyn PartialReflect>]>,
}
impl DynamicArray {
#[inline]
pub fn new(values: Box<[Box<dyn Reflect>]>) -> Self {
pub fn new(values: Box<[Box<dyn PartialReflect>]>) -> Self {
Self {
represented_type: None,
values,
@ -204,7 +204,7 @@ impl DynamicArray {
}
#[deprecated(since = "0.15.0", note = "use from_iter")]
pub fn from_vec<T: Reflect>(values: Vec<T>) -> Self {
pub fn from_vec<T: PartialReflect>(values: Vec<T>) -> Self {
Self::from_iter(values)
}
@ -228,56 +228,47 @@ impl DynamicArray {
}
}
impl Reflect for DynamicArray {
impl PartialReflect for DynamicArray {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> {
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_any(&self) -> &dyn Any {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn Reflect) {
fn apply(&mut self, value: &dyn PartialReflect) {
array_apply(self, value);
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
array_try_apply(self, value)
}
#[inline]
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Array
@ -299,7 +290,7 @@ impl Reflect for DynamicArray {
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
@ -308,7 +299,7 @@ impl Reflect for DynamicArray {
array_hash(self)
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
array_partial_eq(self, value)
}
@ -326,12 +317,12 @@ impl Reflect for DynamicArray {
impl Array for DynamicArray {
#[inline]
fn get(&self, index: usize) -> Option<&dyn Reflect> {
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
self.values.get(index).map(|value| &**value)
}
#[inline]
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
@ -346,7 +337,7 @@ impl Array for DynamicArray {
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.values.into_vec()
}
@ -363,8 +354,8 @@ impl Array for DynamicArray {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicArray {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(values: I) -> Self {
impl FromIterator<Box<dyn PartialReflect>> for DynamicArray {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect::<Vec<_>>().into_boxed_slice(),
@ -372,17 +363,17 @@ impl FromIterator<Box<dyn Reflect>> for DynamicArray {
}
}
impl<T: Reflect> FromIterator<T> for DynamicArray {
impl<T: PartialReflect> FromIterator<T> for DynamicArray {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|value| Box::new(value).into_reflect())
.map(|value| Box::new(value).into_partial_reflect())
.collect()
}
}
impl IntoIterator for DynamicArray {
type Item = Box<dyn Reflect>;
type Item = Box<dyn PartialReflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -391,7 +382,7 @@ impl IntoIterator for DynamicArray {
}
impl<'a> IntoIterator for &'a DynamicArray {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
type IntoIter = ArrayIter<'a>;
fn into_iter(self) -> Self::IntoIter {
@ -400,8 +391,6 @@ impl<'a> IntoIterator for &'a DynamicArray {
}
impl_type_path!((in bevy_reflect) DynamicArray);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicArray);
/// An iterator over an [`Array`].
pub struct ArrayIter<'a> {
@ -418,7 +407,7 @@ impl<'a> ArrayIter<'a> {
}
impl<'a> Iterator for ArrayIter<'a> {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
@ -438,7 +427,7 @@ impl<'a> ExactSizeIterator for ArrayIter<'a> {}
/// Returns the `u64` hash of the given [array](Array).
#[inline]
pub fn array_hash<A: Array>(array: &A) -> Option<u64> {
pub fn array_hash<A: Array + ?Sized>(array: &A) -> Option<u64> {
let mut hasher = reflect_hasher();
Any::type_id(array).hash(&mut hasher);
array.len().hash(&mut hasher);
@ -456,7 +445,7 @@ pub fn array_hash<A: Array>(array: &A) -> Option<u64> {
/// * Panics if the reflected value is not a [valid array](ReflectRef::Array).
///
#[inline]
pub fn array_apply<A: Array>(array: &mut A, reflect: &dyn Reflect) {
pub fn array_apply<A: Array + ?Sized>(array: &mut A, reflect: &dyn PartialReflect) {
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
if array.len() != reflect_array.len() {
panic!("Attempted to apply different sized `Array` types.");
@ -481,7 +470,10 @@ pub fn array_apply<A: Array>(array: &mut A, reflect: &dyn Reflect) {
/// * Returns any error that is generated while applying elements to each other.
///
#[inline]
pub fn array_try_apply<A: Array>(array: &mut A, reflect: &dyn Reflect) -> Result<(), ApplyError> {
pub fn array_try_apply<A: Array>(
array: &mut A,
reflect: &dyn PartialReflect,
) -> Result<(), ApplyError> {
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
if array.len() != reflect_array.len() {
return Err(ApplyError::DifferentSize {
@ -507,7 +499,10 @@ pub fn array_try_apply<A: Array>(array: &mut A, reflect: &dyn Reflect) -> Result
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn array_partial_eq<A: Array>(array: &A, reflect: &dyn Reflect) -> Option<bool> {
pub fn array_partial_eq<A: Array + ?Sized>(
array: &A,
reflect: &dyn PartialReflect,
) -> Option<bool> {
match reflect.reflect_ref() {
ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => {
for (a, b) in array.iter().zip(reflect_array.iter()) {

View file

@ -2,10 +2,10 @@ use bevy_reflect_derive::impl_type_path;
use crate::{
self as bevy_reflect, enum_debug, enum_hash, enum_partial_eq, ApplyError, DynamicStruct,
DynamicTuple, Enum, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple,
TypeInfo, VariantFieldIter, VariantType,
DynamicTuple, Enum, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef,
Struct, Tuple, TypeInfo, VariantFieldIter, VariantType,
};
use std::any::Any;
use std::fmt::Formatter;
/// A dynamic representation of an enum variant.
@ -52,7 +52,7 @@ impl From<()> for DynamicVariant {
/// # Example
///
/// ```
/// # use bevy_reflect::{DynamicEnum, DynamicVariant, Reflect};
/// # use bevy_reflect::{DynamicEnum, DynamicVariant, Reflect, PartialReflect};
///
/// // The original enum value
/// let mut value: Option<usize> = Some(123);
@ -64,7 +64,7 @@ impl From<()> for DynamicVariant {
/// );
///
/// // Apply the DynamicEnum as a patch to the original value
/// value.apply(&dyn_enum);
/// value.apply(dyn_enum.as_partial_reflect());
///
/// // Tada!
/// assert_eq!(None, value);
@ -201,7 +201,7 @@ impl DynamicEnum {
}
impl Enum for DynamicEnum {
fn field(&self, name: &str) -> Option<&dyn Reflect> {
fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
if let DynamicVariant::Struct(data) = &self.variant {
data.field(name)
} else {
@ -209,7 +209,7 @@ impl Enum for DynamicEnum {
}
}
fn field_at(&self, index: usize) -> Option<&dyn Reflect> {
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
if let DynamicVariant::Tuple(data) = &self.variant {
data.field(index)
} else {
@ -217,7 +217,7 @@ impl Enum for DynamicEnum {
}
}
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
if let DynamicVariant::Struct(data) = &mut self.variant {
data.field_mut(name)
} else {
@ -225,7 +225,7 @@ impl Enum for DynamicEnum {
}
}
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
if let DynamicVariant::Tuple(data) = &mut self.variant {
data.field_mut(index)
} else {
@ -287,44 +287,41 @@ impl Enum for DynamicEnum {
}
}
impl Reflect for DynamicEnum {
impl PartialReflect for DynamicEnum {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> {
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_any(&self) -> &dyn Any {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
#[inline]
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::Enum(value) = value.reflect_ref() {
if Enum::variant_name(self) == value.variant_name() {
// Same variant -> just update fields
@ -377,12 +374,6 @@ impl Reflect for DynamicEnum {
Ok(())
}
#[inline]
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Enum
@ -404,7 +395,7 @@ impl Reflect for DynamicEnum {
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
@ -414,7 +405,7 @@ impl Reflect for DynamicEnum {
}
#[inline]
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
enum_partial_eq(self, value)
}
@ -427,5 +418,3 @@ impl Reflect for DynamicEnum {
}
impl_type_path!((in bevy_reflect) DynamicEnum);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicEnum);

View file

@ -1,5 +1,5 @@
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::{DynamicEnum, Reflect, TypePath, TypePathTable, VariantInfo, VariantType};
use crate::{DynamicEnum, PartialReflect, TypePath, TypePathTable, VariantInfo, VariantType};
use bevy_utils::HashMap;
use std::any::{Any, TypeId};
use std::slice::Iter;
@ -89,19 +89,19 @@ use std::sync::Arc;
/// [`None`]: Option<T>::None
/// [`Some`]: Option<T>::Some
/// [`Reflect`]: bevy_reflect_derive::Reflect
pub trait Enum: Reflect {
pub trait Enum: PartialReflect {
/// Returns a reference to the value of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn field(&self, name: &str) -> Option<&dyn Reflect>;
fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
/// Returns a reference to the value of the field (in the current variant) at the given index.
fn field_at(&self, index: usize) -> Option<&dyn Reflect>;
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
/// Returns a mutable reference to the value of the field (in the current variant) at the given index.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the index of the field (in the current variant) with the given name.
///
/// For non-[`VariantType::Struct`] variants, this should return `None`.
@ -307,8 +307,8 @@ impl<'a> Iterator for VariantFieldIter<'a> {
impl<'a> ExactSizeIterator for VariantFieldIter<'a> {}
pub enum VariantField<'a> {
Struct(&'a str, &'a dyn Reflect),
Tuple(&'a dyn Reflect),
Struct(&'a str, &'a dyn PartialReflect),
Tuple(&'a dyn PartialReflect),
}
impl<'a> VariantField<'a> {
@ -320,7 +320,7 @@ impl<'a> VariantField<'a> {
}
}
pub fn value(&self) -> &'a dyn Reflect {
pub fn value(&self) -> &'a dyn PartialReflect {
match *self {
Self::Struct(_, value) | Self::Tuple(value) => value,
}

View file

@ -1,4 +1,5 @@
use crate::{utility::reflect_hasher, Enum, Reflect, ReflectRef, VariantType};
use crate::PartialReflect;
use crate::{utility::reflect_hasher, Enum, ReflectRef, VariantType};
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
@ -15,16 +16,16 @@ pub fn enum_hash<TEnum: Enum>(value: &TEnum) -> Option<u64> {
Some(hasher.finish())
}
/// Compares an [`Enum`] with a [`Reflect`] value.
/// Compares an [`Enum`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is an enum;
/// - `b` is the same variant as `a`;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
#[inline]
pub fn enum_partial_eq<TEnum: Enum>(a: &TEnum, b: &dyn Reflect) -> Option<bool> {
pub fn enum_partial_eq<TEnum: Enum + ?Sized>(a: &TEnum, b: &dyn PartialReflect) -> Option<bool> {
// Both enums?
let ReflectRef::Enum(b) = b.reflect_ref() else {
return Some(false);

View file

@ -614,71 +614,71 @@ mod tests {
C2 { value: f32 },
}
let a: &dyn Reflect = &TestEnum::A;
let b: &dyn Reflect = &TestEnum::A;
let a: &dyn PartialReflect = &TestEnum::A;
let b: &dyn PartialReflect = &TestEnum::A;
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::A == TestEnum::A"
);
let a: &dyn Reflect = &TestEnum::A;
let b: &dyn Reflect = &TestEnum::A1;
let a: &dyn PartialReflect = &TestEnum::A;
let b: &dyn PartialReflect = &TestEnum::A1;
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::A != TestEnum::A1"
);
let a: &dyn Reflect = &TestEnum::B(123);
let b: &dyn Reflect = &TestEnum::B(123);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B(123);
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) == TestEnum::B(123)"
);
let a: &dyn Reflect = &TestEnum::B(123);
let b: &dyn Reflect = &TestEnum::B(321);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B(321);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B(321)"
);
let a: &dyn Reflect = &TestEnum::B(123);
let b: &dyn Reflect = &TestEnum::B1(123);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B1(123);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B1(123)"
);
let a: &dyn Reflect = &TestEnum::B(123);
let b: &dyn Reflect = &TestEnum::B2(123, 123);
let a: &dyn PartialReflect = &TestEnum::B(123);
let b: &dyn PartialReflect = &TestEnum::B2(123, 123);
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::B(123) != TestEnum::B2(123, 123)"
);
let a: &dyn Reflect = &TestEnum::C { value: 123 };
let b: &dyn Reflect = &TestEnum::C { value: 123 };
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C { value: 123 };
assert!(
a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} == TestEnum::C{{value: 123}}"
);
let a: &dyn Reflect = &TestEnum::C { value: 123 };
let b: &dyn Reflect = &TestEnum::C { value: 321 };
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C { value: 321 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C{{value: 321}}"
);
let a: &dyn Reflect = &TestEnum::C { value: 123 };
let b: &dyn Reflect = &TestEnum::C1 { value: 123 };
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C1 { value: 123 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C1{{value: 123}}"
);
let a: &dyn Reflect = &TestEnum::C { value: 123 };
let b: &dyn Reflect = &TestEnum::C2 { value: 1.23 };
let a: &dyn PartialReflect = &TestEnum::C { value: 123 };
let b: &dyn PartialReflect = &TestEnum::C2 { value: 1.23 };
assert!(
!a.reflect_partial_eq(b).unwrap_or_default(),
"expected TestEnum::C{{value: 123}} != TestEnum::C2{{value: 1.23}}"

View file

@ -1,5 +1,5 @@
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::{MaybeTyped, Reflect, TypeInfo, TypePath, TypePathTable};
use crate::{MaybeTyped, PartialReflect, TypeInfo, TypePath, TypePathTable};
use std::any::{Any, TypeId};
use std::sync::Arc;
@ -17,7 +17,7 @@ pub struct NamedField {
impl NamedField {
/// Create a new [`NamedField`].
pub fn new<T: Reflect + MaybeTyped + TypePath>(name: &'static str) -> Self {
pub fn new<T: PartialReflect + MaybeTyped + TypePath>(name: &'static str) -> Self {
Self {
name,
type_info: T::maybe_type_info,
@ -106,7 +106,7 @@ pub struct UnnamedField {
}
impl UnnamedField {
pub fn new<T: Reflect + MaybeTyped + TypePath>(index: usize) -> Self {
pub fn new<T: PartialReflect + MaybeTyped + TypePath>(index: usize) -> Self {
Self {
index,
type_info: T::maybe_type_info,

View file

@ -1,4 +1,4 @@
use crate::{FromType, Reflect};
use crate::{FromType, PartialReflect, Reflect};
/// A trait that enables types to be dynamically constructed from reflected data.
///
@ -27,7 +27,7 @@ use crate::{FromType, Reflect};
)]
pub trait FromReflect: Reflect + Sized {
/// Constructs a concrete instance of `Self` from a reflected value.
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self>;
/// Attempts to downcast the given value to `Self` using,
/// constructing the value using [`from_reflect`] if that fails.
@ -39,8 +39,10 @@ pub trait FromReflect: Reflect + Sized {
/// [`from_reflect`]: Self::from_reflect
/// [`DynamicStruct`]: crate::DynamicStruct
/// [`DynamicList`]: crate::DynamicList
fn take_from_reflect(reflect: Box<dyn Reflect>) -> Result<Self, Box<dyn Reflect>> {
match reflect.take::<Self>() {
fn take_from_reflect(
reflect: Box<dyn PartialReflect>,
) -> Result<Self, Box<dyn PartialReflect>> {
match reflect.try_take::<Self>() {
Ok(value) => Ok(value),
Err(value) => match Self::from_reflect(value.as_ref()) {
None => Err(value),
@ -101,7 +103,7 @@ pub trait FromReflect: Reflect + Sized {
/// [`DynamicEnum`]: crate::DynamicEnum
#[derive(Clone)]
pub struct ReflectFromReflect {
from_reflect: fn(&dyn Reflect) -> Option<Box<dyn Reflect>>,
from_reflect: fn(&dyn PartialReflect) -> Option<Box<dyn Reflect>>,
}
impl ReflectFromReflect {
@ -110,7 +112,7 @@ impl ReflectFromReflect {
/// This will convert the object to a concrete type if it wasn't already, and return
/// the value as `Box<dyn Reflect>`.
#[allow(clippy::wrong_self_convention)]
pub fn from_reflect(&self, reflect_value: &dyn Reflect) -> Option<Box<dyn Reflect>> {
pub fn from_reflect(&self, reflect_value: &dyn PartialReflect) -> Option<Box<dyn Reflect>> {
(self.from_reflect)(reflect_value)
}
}

View file

@ -1,5 +1,5 @@
use crate::func::args::{ArgError, FromArg, Ownership};
use crate::{Reflect, TypePath};
use crate::{PartialReflect, Reflect, TypePath};
use std::ops::Deref;
/// Represents an argument that can be passed to a [`DynamicFunction`], [`DynamicClosure`],
@ -83,7 +83,7 @@ impl<'a> Arg<'a> {
/// ```
pub fn take_owned<T: Reflect + TypePath>(self) -> Result<T, ArgError> {
match self.value {
ArgValue::Owned(arg) => arg.take().map_err(|arg| ArgError::UnexpectedType {
ArgValue::Owned(arg) => arg.try_take().map_err(|arg| ArgError::UnexpectedType {
index: self.index,
expected: std::borrow::Cow::Borrowed(T::type_path()),
received: std::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
@ -124,11 +124,13 @@ impl<'a> Arg<'a> {
received: Ownership::Owned,
}),
ArgValue::Ref(arg) => {
Ok(arg.downcast_ref().ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: std::borrow::Cow::Borrowed(T::type_path()),
received: std::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
})?)
Ok(arg
.try_downcast_ref()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: std::borrow::Cow::Borrowed(T::type_path()),
received: std::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
})?)
}
ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
index: self.index,
@ -167,11 +169,13 @@ impl<'a> Arg<'a> {
}),
ArgValue::Mut(arg) => {
let received = std::borrow::Cow::Owned(arg.reflect_type_path().to_string());
Ok(arg.downcast_mut().ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: std::borrow::Cow::Borrowed(T::type_path()),
received,
})?)
Ok(arg
.try_downcast_mut()
.ok_or_else(|| ArgError::UnexpectedType {
index: self.index,
expected: std::borrow::Cow::Borrowed(T::type_path()),
received,
})?)
}
}
}
@ -182,13 +186,13 @@ impl<'a> Arg<'a> {
/// [`DynamicFunction`]: crate::func::DynamicFunction
#[derive(Debug)]
pub enum ArgValue<'a> {
Owned(Box<dyn Reflect>),
Ref(&'a dyn Reflect),
Mut(&'a mut dyn Reflect),
Owned(Box<dyn PartialReflect>),
Ref(&'a dyn PartialReflect),
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Deref for ArgValue<'a> {
type Target = dyn Reflect;
type Target = dyn PartialReflect;
fn deref(&self) -> &Self::Target {
match self {

View file

@ -1,6 +1,6 @@
use crate::func::args::{Arg, ArgValue, FromArg};
use crate::func::ArgError;
use crate::{Reflect, TypePath};
use crate::{PartialReflect, Reflect, TypePath};
use std::collections::VecDeque;
/// A list of arguments that can be passed to a [`DynamicFunction`], [`DynamicClosure`],
@ -70,7 +70,7 @@ impl<'a> ArgList<'a> {
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_ref(self, arg: &'a dyn Reflect) -> Self {
pub fn push_ref(self, arg: &'a dyn PartialReflect) -> Self {
self.push_arg(ArgValue::Ref(arg))
}
@ -78,7 +78,7 @@ impl<'a> ArgList<'a> {
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_mut(self, arg: &'a mut dyn Reflect) -> Self {
pub fn push_mut(self, arg: &'a mut dyn PartialReflect) -> Self {
self.push_arg(ArgValue::Mut(arg))
}
@ -86,7 +86,7 @@ impl<'a> ArgList<'a> {
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_owned(self, arg: impl Reflect) -> Self {
pub fn push_owned(self, arg: impl PartialReflect) -> Self {
self.push_arg(ArgValue::Owned(Box::new(arg)))
}
@ -94,7 +94,7 @@ impl<'a> ArgList<'a> {
///
/// If an argument was previously removed from the beginning of the list,
/// this method will also re-index the list.
pub fn push_boxed(self, arg: Box<dyn Reflect>) -> Self {
pub fn push_boxed(self, arg: Box<dyn PartialReflect>) -> Self {
self.push_arg(ArgValue::Owned(arg))
}

View file

@ -40,7 +40,7 @@ use crate::func::{FunctionResult, IntoClosure, ReturnInfo};
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.take::<String>().unwrap(), "Hello, world!!!");
/// assert_eq!(value.try_take::<String>().unwrap(), "Hello, world!!!");
/// ```
///
/// [`DynamicClosureMut`]: crate::func::closures::DynamicClosureMut
@ -110,7 +110,7 @@ impl<'env> DynamicClosure<'env> {
/// let mut func = add.into_closure().with_name("add");
/// let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.take::<i32>().unwrap(), 123);
/// assert_eq!(result.try_take::<i32>().unwrap(), 123);
/// ```
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
(self.func)(args)

View file

@ -42,7 +42,7 @@ use crate::func::{FunctionResult, IntoClosureMut, ReturnInfo};
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.take::<i32>().unwrap(), 2);
/// assert_eq!(value.try_take::<i32>().unwrap(), 2);
///
/// // Note that `func` still has a reference to `list`,
/// // so we need to drop it before we can access `list` again.
@ -125,7 +125,7 @@ impl<'env> DynamicClosureMut<'env> {
/// let mut func = add.into_closure_mut().with_name("add");
/// let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.take::<i32>().unwrap(), 100);
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
/// ```
///
/// [`call_once`]: DynamicClosureMut::call_once

View file

@ -36,7 +36,7 @@ mod tests {
let func = (|a: i32, b: i32| a + b + c).into_closure();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&123));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -48,7 +48,7 @@ mod tests {
let func = add.into_closure();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&100));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]

View file

@ -40,7 +40,7 @@ mod tests {
let func = (|a: i32, b: i32| a + b + c).into_closure();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&123));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -61,7 +61,7 @@ mod tests {
let mut func = add.into_closure_mut();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&100));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]

View file

@ -41,7 +41,7 @@ use crate::func::{FunctionResult, IntoFunction, ReturnInfo};
/// let value = func.call(args).unwrap().unwrap_owned();
///
/// // Check the result:
/// assert_eq!(value.downcast_ref::<i32>(), Some(&100));
/// assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
/// ```
///
/// However, in some cases, these functions may need to be created manually:
@ -82,7 +82,7 @@ use crate::func::{FunctionResult, IntoFunction, ReturnInfo};
/// let value = func.call(args).unwrap().unwrap_mut();
///
/// // Mutate the return value:
/// value.downcast_mut::<String>().unwrap().push_str("!!!");
/// value.try_downcast_mut::<String>().unwrap().push_str("!!!");
///
/// // Check the result:
/// assert_eq!(list, vec!["Hello, World!!!"]);
@ -151,7 +151,7 @@ impl DynamicFunction {
/// let func = add.into_function();
/// let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
/// let result = func.call(args).unwrap().unwrap_owned();
/// assert_eq!(result.take::<i32>().unwrap(), 100);
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
/// ```
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
(self.func)(args)
@ -269,7 +269,7 @@ mod tests {
.call(ArgList::new().push_owned(0_usize).push_ref(&list))
.unwrap()
.unwrap_ref()
.downcast_ref::<String>()
.try_downcast_ref::<String>()
.unwrap();
assert_eq!(value, "foo");
}

View file

@ -67,7 +67,7 @@ mod tests {
let func = add.into_function();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&100));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
@ -79,7 +79,7 @@ mod tests {
let func = (add as fn(i32, i32) -> i32).into_function();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&100));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
@ -87,7 +87,7 @@ mod tests {
let func = (|a: i32, b: i32| a + b).into_function();
let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<i32>(), Some(&100));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
}
#[test]
@ -107,7 +107,7 @@ mod tests {
let func = Foo::add.into_function();
let args = ArgList::new().push_ref(&foo_a).push_ref(&foo_b);
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(result.downcast_ref::<Foo>(), Some(&Foo(100)));
assert_eq!(result.try_downcast_ref::<Foo>(), Some(&Foo(100)));
}
#[test]
@ -120,7 +120,7 @@ mod tests {
let args = ArgList::new();
let result = func.call(args).unwrap().unwrap_owned();
assert_eq!(
result.downcast_ref::<String>(),
result.try_downcast_ref::<String>(),
Some(&String::from("Hello, World!"))
);
}
@ -148,7 +148,7 @@ mod tests {
.push_owned(String::from("Hello, World!"))
.push_ref(&true);
let result = func.call(args).unwrap().unwrap_ref();
assert_eq!(result.downcast_ref::<i32>(), Some(&123));
assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -164,7 +164,7 @@ mod tests {
.push_owned(String::from("Hello, World!"))
.push_ref(&true);
let result = func.call(args).unwrap().unwrap_mut();
assert_eq!(result.downcast_mut::<i32>(), Some(&mut 123));
assert_eq!(result.try_downcast_mut::<i32>(), Some(&mut 123));
}
#[test]

View file

@ -10,12 +10,12 @@
//! via an [`ArgList`].
//!
//! This returns a [`FunctionResult`] containing the [`Return`] value,
//! which can be used to extract a [`Reflect`] trait object.
//! which can be used to extract a [`PartialReflect`] trait object.
//!
//! # Example
//!
//! ```
//! # use bevy_reflect::Reflect;
//! # use bevy_reflect::PartialReflect;
//! # use bevy_reflect::func::args::ArgList;
//! # use bevy_reflect::func::{DynamicFunction, FunctionResult, IntoFunction, Return};
//! fn add(a: i32, b: i32) -> i32 {
@ -27,10 +27,10 @@
//! // Pushing a known type with owned ownership
//! .push_owned(25_i32)
//! // Pushing a reflected type with owned ownership
//! .push_boxed(Box::new(75_i32) as Box<dyn Reflect>);
//! .push_boxed(Box::new(75_i32) as Box<dyn PartialReflect>);
//! let result: FunctionResult = func.call(args);
//! let value: Return = result.unwrap();
//! assert_eq!(value.unwrap_owned().downcast_ref::<i32>(), Some(&100));
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&100));
//! ```
//!
//! # Functions vs Closures
@ -95,6 +95,7 @@
//! For other functions that don't conform to one of the above signatures,
//! [`DynamicFunction`] and [`DynamicClosure`] can instead be created manually.
//!
//! [`PartialReflect`]: crate::PartialReflect
//! [`Reflect`]: crate::Reflect
//! [lack of variadic generics]: https://poignardazur.github.io/2024/05/25/report-on-rustnl-variadics/
//! [coherence issues]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#coherence-leak-check

View file

@ -42,7 +42,7 @@ use crate::{Reflect, TypePath};
/// let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
///
/// let value = add.reflect_call(args).unwrap().unwrap_owned();
/// assert_eq!(value.take::<i32>().unwrap(), 100);
/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
/// ```
///
/// # Trait Parameters

View file

@ -351,7 +351,7 @@ mod tests {
let function = registry.get(std::any::type_name_of_val(&foo)).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.downcast_ref::<i32>(), Some(&123));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -361,7 +361,7 @@ mod tests {
let function = registry.get("foo").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.downcast_ref::<i32>(), Some(&123));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -377,7 +377,7 @@ mod tests {
let function = registry.get("custom_name").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.downcast_ref::<i32>(), Some(&123));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -404,7 +404,7 @@ mod tests {
let function = registry.get(name).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.downcast_ref::<i32>(), Some(&123));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
}
#[test]
@ -429,7 +429,7 @@ mod tests {
let function = registry.get(name).unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.downcast_ref::<i32>(), Some(&321));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&321));
}
#[test]

View file

@ -1,4 +1,4 @@
use crate::Reflect;
use crate::PartialReflect;
/// The return type of a [`DynamicFunction`] or [`DynamicClosure`].
///
@ -9,11 +9,11 @@ pub enum Return<'a> {
/// The function returns nothing (i.e. it returns `()`).
Unit,
/// The function returns an owned value.
Owned(Box<dyn Reflect>),
Owned(Box<dyn PartialReflect>),
/// The function returns a reference to a value.
Ref(&'a dyn Reflect),
Ref(&'a dyn PartialReflect),
/// The function returns a mutable reference to a value.
Mut(&'a mut dyn Reflect),
Mut(&'a mut dyn PartialReflect),
}
impl<'a> Return<'a> {
@ -27,7 +27,7 @@ impl<'a> Return<'a> {
/// # Panics
///
/// Panics if the return value is not [`Self::Owned`].
pub fn unwrap_owned(self) -> Box<dyn Reflect> {
pub fn unwrap_owned(self) -> Box<dyn PartialReflect> {
match self {
Return::Owned(value) => value,
_ => panic!("expected owned value"),
@ -39,7 +39,7 @@ impl<'a> Return<'a> {
/// # Panics
///
/// Panics if the return value is not [`Self::Ref`].
pub fn unwrap_ref(self) -> &'a dyn Reflect {
pub fn unwrap_ref(self) -> &'a dyn PartialReflect {
match self {
Return::Ref(value) => value,
_ => panic!("expected reference value"),
@ -51,7 +51,7 @@ impl<'a> Return<'a> {
/// # Panics
///
/// Panics if the return value is not [`Self::Mut`].
pub fn unwrap_mut(self) -> &'a mut dyn Reflect {
pub fn unwrap_mut(self) -> &'a mut dyn PartialReflect {
match self {
Return::Mut(value) => value,
_ => panic!("expected mutable reference value"),

View file

@ -6,32 +6,32 @@ use std::any::Any;
use crate::utility::GenericTypeInfoCell;
use crate::{
self as bevy_reflect, ApplyError, FromReflect, FromType, GetTypeRegistration, List, ListInfo,
ListIter, MaybeTyped, Reflect, ReflectFromPtr, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo, TypePath, TypeRegistration, Typed,
ListIter, MaybeTyped, PartialReflect, Reflect, ReflectFromPtr, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypeRegistration, Typed,
};
impl<T: SmallArray + TypePath + Send + Sync> List for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn get(&self, index: usize) -> Option<&dyn Reflect> {
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
if index < SmallVec::len(self) {
Some(&self[index] as &dyn Reflect)
Some(&self[index] as &dyn PartialReflect)
} else {
None
}
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
if index < SmallVec::len(self) {
Some(&mut self[index] as &mut dyn Reflect)
Some(&mut self[index] as &mut dyn PartialReflect)
} else {
None
}
}
fn insert(&mut self, index: usize, value: Box<dyn Reflect>) {
let value = value.take::<T::Item>().unwrap_or_else(|value| {
fn insert(&mut self, index: usize, value: Box<dyn PartialReflect>) {
let value = value.try_take::<T::Item>().unwrap_or_else(|value| {
<T as SmallArray>::Item::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"Attempted to insert invalid value of type {}.",
@ -42,12 +42,12 @@ where
SmallVec::insert(self, index, value);
}
fn remove(&mut self, index: usize) -> Box<dyn Reflect> {
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
Box::new(self.remove(index))
}
fn push(&mut self, value: Box<dyn Reflect>) {
let value = value.take::<T::Item>().unwrap_or_else(|value| {
fn push(&mut self, value: Box<dyn PartialReflect>) {
let value = value.try_take::<T::Item>().unwrap_or_else(|value| {
<T as SmallArray>::Item::from_reflect(&*value).unwrap_or_else(|| {
panic!(
"Attempted to push invalid value of type {}.",
@ -58,8 +58,9 @@ where
SmallVec::push(self, value);
}
fn pop(&mut self) -> Option<Box<dyn Reflect>> {
self.pop().map(|value| Box::new(value) as Box<dyn Reflect>)
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
self.pop()
.map(|value| Box::new(value) as Box<dyn PartialReflect>)
}
fn len(&self) -> usize {
@ -70,14 +71,13 @@ where
ListIter::new(self)
}
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.into_iter()
.map(|value| Box::new(value) as Box<dyn Reflect>)
.map(|value| Box::new(value) as Box<dyn PartialReflect>)
.collect()
}
}
impl<T: SmallArray + TypePath + Send + Sync> Reflect for SmallVec<T>
impl<T: SmallArray + TypePath + Send + Sync> PartialReflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
@ -85,6 +85,68 @@ where
Some(<Self as Typed>::type_info())
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Ok(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
Some(self)
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
Some(self)
}
fn apply(&mut self, value: &dyn PartialReflect) {
crate::list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
crate::list_try_apply(self, value)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::List(self)
}
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
crate::list_partial_eq(self, value)
}
}
impl<T: SmallArray + TypePath + Send + Sync> Reflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
@ -109,42 +171,10 @@ where
self
}
fn apply(&mut self, value: &dyn Reflect) {
crate::list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
crate::list_try_apply(self, value)
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::List(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
crate::list_partial_eq(self, value)
}
}
impl<T: SmallArray + TypePath + Send + Sync + 'static> Typed for SmallVec<T>
@ -163,7 +193,7 @@ impl<T: SmallArray + TypePath + Send + Sync> FromReflect for SmallVec<T>
where
T::Item: FromReflect + MaybeTyped + TypePath,
{
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
let mut new_list = Self::with_capacity(ref_list.len());
for field in ref_list.iter() {

View file

@ -6,14 +6,14 @@ impl_reflect_value!(::smol_str::SmolStr(Debug, Hash, PartialEq, Default));
#[cfg(test)]
mod tests {
use crate::{FromReflect, Reflect};
use crate::{FromReflect, PartialReflect};
use smol_str::SmolStr;
#[test]
fn should_partial_eq_smolstr() {
let a: &dyn Reflect = &SmolStr::new("A");
let a2: &dyn Reflect = &SmolStr::new("A");
let b: &dyn Reflect = &SmolStr::new("B");
let a: &dyn PartialReflect = &SmolStr::new("A");
let a2: &dyn PartialReflect = &SmolStr::new("A");
let b: &dyn PartialReflect = &SmolStr::new("B");
assert_eq!(Some(true), a.reflect_partial_eq(a2));
assert_eq!(Some(false), a.reflect_partial_eq(b));
}

File diff suppressed because it is too large Load diff

View file

@ -26,15 +26,60 @@
//! It's important to note that because of missing features in Rust,
//! there are some [limitations] with this crate.
//!
//! # The `Reflect` Trait
//! # The `Reflect` and `PartialReflect` traits
//!
//! At the core of [`bevy_reflect`] is the [`Reflect`] trait.
//! At the root of [`bevy_reflect`] is the [`PartialReflect`] trait.
//!
//! One of its primary purposes is to allow all implementors to be passed around
//! as a `dyn Reflect` trait object.
//! This allows any such type to be operated upon completely dynamically (at a small [runtime cost]).
//! Its purpose is to allow dynamic [introspection] of values,
//! following Rust's type system through a system of [subtraits].
//!
//! Implementing the trait is easily done using the provided [derive macro]:
//! Its primary purpose is to allow all implementors to be passed around
//! as a `dyn PartialReflect` trait object in one of the following forms:
//! * `&dyn PartialReflect`
//! * `&mut dyn PartialReflect`
//! * `Box<dyn PartialReflect>`
//!
//! This allows values of types implementing `PartialReflect`
//! to be operated upon completely dynamically (at a small [runtime cost]).
//!
//! Building on `PartialReflect` is the [`Reflect`] trait.
//!
//! `PartialReflect` is a supertrait of `Reflect`
//! so any type implementing `Reflect` implements `PartialReflect` by definition.
//! `dyn Reflect` trait objects can be used similarly to `dyn PartialReflect`,
//! but `Reflect` is also often used in trait bounds (like `T: Reflect`).
//!
//! The distinction between `PartialReflect` and `Reflect` is summarised in the following:
//! * `PartialReflect` is a trait for interacting with values under `bevy_reflect`'s data model.
//! This means values implementing `PartialReflect` can be dynamically constructed and introspected.
//! * The `Reflect` trait, however, ensures that the interface exposed by `PartialReflect`
//! on types which additionally implement `Reflect` mirrors the structure of a single Rust type.
//! * This means `dyn Reflect` trait objects can be directly downcasted to concrete types,
//! where `dyn PartialReflect` trait object cannot.
//! * `Reflect`, since it provides a stronger type-correctness guarantee,
//! is the trait used to interact with [the type registry].
//!
//! ## Converting between `PartialReflect` and `Reflect`
//!
//! Since `T: Reflect` implies `T: PartialReflect`, conversion from a `dyn Reflect` to a `dyn PartialReflect`
//! trait object (upcasting) is infallible and can be performed with one of the following methods.
//! Note that these are temporary while [the language feature for dyn upcasting coercion] is experimental:
//! * [`PartialReflect::as_partial_reflect`] for `&dyn PartialReflect`
//! * [`PartialReflect::as_partial_reflect_mut`] for `&mut dyn PartialReflect`
//! * [`PartialReflect::into_partial_reflect`] for `Box<dyn PartialReflect>`
//!
//! For conversion in the other direction — downcasting `dyn PartialReflect` to `dyn Reflect` —
//! there are fallible methods:
//! * [`PartialReflect::try_as_reflect`] for `&dyn Reflect`
//! * [`PartialReflect::try_as_reflect_mut`] for `&mut dyn Reflect`
//! * [`PartialReflect::try_into_reflect`] for `Box<dyn Reflect>`
//!
//! Additionally, [`FromReflect::from_reflect`] can be used to convert a `dyn PartialReflect` to a concrete type
//! which implements `Reflect`.
//!
//! # Implementing `Reflect`
//!
//! Implementing `Reflect` (and `PartialReflect`) is easily done using the provided [derive macro]:
//!
//! ```
//! # use bevy_reflect::Reflect;
@ -54,8 +99,8 @@
//! ## Requirements
//!
//! We can implement `Reflect` on any type that satisfies _both_ of the following conditions:
//! * The type implements `Any`.
//! This is true if and only if the type itself has a [`'static` lifetime].
//! * The type implements `Any`, `Send`, and `Sync`.
//! For the `Any` requirement to be satisfied, the type itself must have a [`'static` lifetime].
//! * All fields and sub-elements themselves implement `Reflect`
//! (see the [derive macro documentation] for details on how to ignore certain fields when deriving).
//!
@ -63,11 +108,11 @@
//! * All fields and sub-elements must implement [`FromReflect`]—
//! another important reflection trait discussed in a later section.
//!
//! # The `Reflect` Subtraits
//! # The Reflection Subtraits
//!
//! Since [`Reflect`] is meant to cover any and every type, this crate also comes with a few
//! more traits to accompany `Reflect` and provide more specific interactions.
//! We refer to these traits as the _reflection subtraits_ since they all have `Reflect` as a supertrait.
//! Since [`PartialReflect`] is meant to cover any and every type, this crate also comes with a few
//! more traits to accompany `PartialReflect` and provide more specific interactions.
//! We refer to these traits as the _reflection subtraits_ since they all have `PartialReflect` as a supertrait.
//! The current list of reflection subtraits include:
//! * [`Tuple`]
//! * [`Array`]
@ -83,7 +128,7 @@
//! For example, we can access our struct's fields by name using the [`Struct::field`] method.
//!
//! ```
//! # use bevy_reflect::{Reflect, Struct};
//! # use bevy_reflect::{PartialReflect, Reflect, Struct};
//! # #[derive(Reflect)]
//! # struct MyStruct {
//! # foo: i32
@ -91,28 +136,29 @@
//! let my_struct: Box<dyn Struct> = Box::new(MyStruct {
//! foo: 123
//! });
//! let foo: &dyn Reflect = my_struct.field("foo").unwrap();
//! assert_eq!(Some(&123), foo.downcast_ref::<i32>());
//! let foo: &dyn PartialReflect = my_struct.field("foo").unwrap();
//! assert_eq!(Some(&123), foo.try_downcast_ref::<i32>());
//! ```
//!
//! Since most data is passed around as `dyn Reflect`,
//! the `Reflect` trait has methods for going to and from these subtraits.
//! Since most data is passed around as `dyn PartialReflect` or `dyn Reflect` trait objects,
//! the `PartialReflect` trait has methods for going to and from these subtraits.
//!
//! [`Reflect::reflect_kind`], [`Reflect::reflect_ref`], [`Reflect::reflect_mut`], and [`Reflect::reflect_owned`] all return
//! [`PartialReflect::reflect_kind`], [`PartialReflect::reflect_ref`],
//! [`PartialReflect::reflect_mut`], and [`PartialReflect::reflect_owned`] all return
//! an enum that respectively contains zero-sized, immutable, mutable, and owned access to the type as a subtrait object.
//!
//! For example, we can get out a `dyn Tuple` from our reflected tuple type using one of these methods.
//!
//! ```
//! # use bevy_reflect::{Reflect, ReflectRef};
//! let my_tuple: Box<dyn Reflect> = Box::new((1, 2, 3));
//! # use bevy_reflect::{PartialReflect, ReflectRef};
//! let my_tuple: Box<dyn PartialReflect> = Box::new((1, 2, 3));
//! let ReflectRef::Tuple(my_tuple) = my_tuple.reflect_ref() else { unreachable!() };
//! assert_eq!(3, my_tuple.field_len());
//! ```
//!
//! And to go back to a general-purpose `dyn Reflect`,
//! we can just use the matching [`Reflect::as_reflect`], [`Reflect::as_reflect_mut`],
//! or [`Reflect::into_reflect`] methods.
//! And to go back to a general-purpose `dyn PartialReflect`,
//! we can just use the matching [`PartialReflect::as_partial_reflect`], [`PartialReflect::as_partial_reflect_mut`],
//! or [`PartialReflect::into_partial_reflect`] methods.
//!
//! ## Value Types
//!
@ -120,7 +166,7 @@
//! such as for primitives (e.g. `bool`, `usize`, etc.)
//! and simple types (e.g. `String`, `Duration`),
//! are referred to as _value_ types
//! since methods like [`Reflect::reflect_ref`] return a [`ReflectRef::Value`] variant.
//! since methods like [`PartialReflect::reflect_ref`] return a [`ReflectRef::Value`] variant.
//! While most other types contain their own `dyn Reflect` fields and data,
//! these types generally cannot be broken down any further.
//!
@ -143,18 +189,18 @@
//! # use bevy_reflect::{DynamicStruct, Struct};
//! let mut data = DynamicStruct::default();
//! data.insert("foo", 123_i32);
//! assert_eq!(Some(&123), data.field("foo").unwrap().downcast_ref::<i32>())
//! assert_eq!(Some(&123), data.field("foo").unwrap().try_downcast_ref::<i32>())
//! ```
//!
//! They are most commonly used as "proxies" for other types,
//! where they contain the same data as— and therefore, represent— a concrete type.
//! The [`Reflect::clone_value`] method will return a dynamic type for all non-value types,
//! The [`PartialReflect::clone_value`] method will return a dynamic type for all non-value types,
//! allowing all types to essentially be "cloned".
//! And since dynamic types themselves implement [`Reflect`],
//! we may pass them around just like any other reflected type.
//! And since dynamic types themselves implement [`PartialReflect`],
//! we may pass them around just like most other reflected types.
//!
//! ```
//! # use bevy_reflect::{DynamicStruct, Reflect};
//! # use bevy_reflect::{DynamicStruct, PartialReflect, Reflect};
//! # #[derive(Reflect)]
//! # struct MyStruct {
//! # foo: i32
@ -164,18 +210,17 @@
//! });
//!
//! // `cloned` will be a `DynamicStruct` representing a `MyStruct`
//! let cloned: Box<dyn Reflect> = original.clone_value();
//! let cloned: Box<dyn PartialReflect> = original.clone_value();
//! assert!(cloned.represents::<MyStruct>());
//! assert!(cloned.is::<DynamicStruct>());
//! ```
//!
//! ## Patching
//!
//! These dynamic types come in handy when needing to apply multiple changes to another type.
//! This is known as "patching" and is done using the [`Reflect::apply`] and [`Reflect::try_apply`] methods.
//! This is known as "patching" and is done using the [`PartialReflect::apply`] and [`PartialReflect::try_apply`] methods.
//!
//! ```
//! # use bevy_reflect::{DynamicEnum, Reflect};
//! # use bevy_reflect::{DynamicEnum, PartialReflect};
//! let mut value = Some(123_i32);
//! let patch = DynamicEnum::new("None", ());
//! value.apply(&patch);
@ -189,7 +234,7 @@
//! or when trying to make use of a reflected trait which expects the actual type.
//!
//! ```should_panic
//! # use bevy_reflect::{DynamicStruct, Reflect};
//! # use bevy_reflect::{DynamicStruct, PartialReflect, Reflect};
//! # #[derive(Reflect)]
//! # struct MyStruct {
//! # foo: i32
@ -198,8 +243,8 @@
//! foo: 123
//! });
//!
//! let cloned: Box<dyn Reflect> = original.clone_value();
//! let value = cloned.take::<MyStruct>().unwrap(); // PANIC!
//! let cloned: Box<dyn PartialReflect> = original.clone_value();
//! let value = cloned.try_take::<MyStruct>().unwrap(); // PANIC!
//! ```
//!
//! To resolve this issue, we'll need to convert the dynamic type to the concrete one.
@ -214,7 +259,7 @@
//! using `#[reflect(from_reflect = false)]` on the item.
//!
//! ```
//! # use bevy_reflect::{Reflect, FromReflect};
//! # use bevy_reflect::{FromReflect, PartialReflect, Reflect};
//! #[derive(Reflect)]
//! struct MyStruct {
//! foo: i32
@ -223,7 +268,7 @@
//! foo: 123
//! });
//!
//! let cloned: Box<dyn Reflect> = original.clone_value();
//! let cloned: Box<dyn PartialReflect> = original.clone_value();
//! let value = <MyStruct as FromReflect>::from_reflect(&*cloned).unwrap(); // OK!
//! ```
//!
@ -239,7 +284,7 @@
//!
//! # Path navigation
//!
//! The [`GetPath`] trait allows accessing arbitrary nested fields of a [`Reflect`] type.
//! The [`GetPath`] trait allows accessing arbitrary nested fields of an [`PartialReflect`] type.
//!
//! Using `GetPath`, it is possible to use a path string to access a specific field
//! of a reflected type.
@ -306,7 +351,8 @@
//! ## Reflecting Traits
//!
//! Type data doesn't have to be tied to a trait, but it's often extremely useful to create trait type data.
//! These allow traits to be used directly on a `dyn Reflect` while utilizing the underlying type's implementation.
//! These allow traits to be used directly on a `dyn Reflect` (and not a `dyn PartialReflect`)
//! while utilizing the underlying type's implementation.
//!
//! For any [object-safe] trait, we can easily generate a corresponding `ReflectTrait` type for our trait
//! using the [`#[reflect_trait]`](reflect_trait) macro.
@ -358,7 +404,7 @@
//! # use serde::de::DeserializeSeed;
//! # use bevy_reflect::{
//! # serde::{ReflectSerializer, ReflectDeserializer},
//! # Reflect, FromReflect, TypeRegistry
//! # Reflect, PartialReflect, FromReflect, TypeRegistry
//! # };
//! #[derive(Reflect, PartialEq, Debug)]
//! struct MyStruct {
@ -374,12 +420,12 @@
//! registry.register::<MyStruct>();
//!
//! // Serialize
//! let reflect_serializer = ReflectSerializer::new(&original_value, &registry);
//! let reflect_serializer = ReflectSerializer::new(original_value.as_partial_reflect(), &registry);
//! let serialized_value: String = ron::to_string(&reflect_serializer).unwrap();
//!
//! // Deserialize
//! let reflect_deserializer = ReflectDeserializer::new(&registry);
//! let deserialized_value: Box<dyn Reflect> = reflect_deserializer.deserialize(
//! let deserialized_value: Box<dyn PartialReflect> = reflect_deserializer.deserialize(
//! &mut ron::Deserializer::from_str(&serialized_value).unwrap()
//! ).unwrap();
//!
@ -449,7 +495,11 @@
//! [Bevy]: https://bevyengine.org/
//! [limitations]: #limitations
//! [`bevy_reflect`]: crate
//! [introspection]: https://en.wikipedia.org/wiki/Type_introspection
//! [subtraits]: #the-reflection-subtraits
//! [the type registry]: #type-registration
//! [runtime cost]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch
//! [the language feature for dyn upcasting coercion]: https://github.com/rust-lang/rust/issues/65991
//! [derive macro]: derive@crate::Reflect
//! [`'static` lifetime]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound
//! [derive macro documentation]: derive@crate::Reflect
@ -515,9 +565,9 @@ pub mod prelude {
pub use crate::std_traits::*;
#[doc(hidden)]
pub use crate::{
reflect_trait, FromReflect, GetField, GetPath, GetTupleStructField, Reflect,
ReflectDeserialize, ReflectFromReflect, ReflectPath, ReflectSerialize, Struct, TupleStruct,
TypePath,
reflect_trait, FromReflect, GetField, GetPath, GetTupleStructField, PartialReflect,
Reflect, ReflectDeserialize, ReflectFromReflect, ReflectPath, ReflectSerialize, Struct,
TupleStruct, TypePath,
};
#[cfg(feature = "functions")]
@ -732,10 +782,19 @@ mod tests {
let mut map = DynamicMap::default();
map.insert(key_a, 10u32);
assert_eq!(10, *map.get(&key_b).unwrap().downcast_ref::<u32>().unwrap());
assert_eq!(
10,
*map.get(&key_b).unwrap().try_downcast_ref::<u32>().unwrap()
);
assert!(map.get(&key_c).is_none());
*map.get_mut(&key_b).unwrap().downcast_mut::<u32>().unwrap() = 20;
assert_eq!(20, *map.get(&key_b).unwrap().downcast_ref::<u32>().unwrap());
*map.get_mut(&key_b)
.unwrap()
.try_downcast_mut::<u32>()
.unwrap() = 20;
assert_eq!(
20,
*map.get(&key_b).unwrap().try_downcast_ref::<u32>().unwrap()
);
}
#[test]
@ -751,16 +810,22 @@ mod tests {
let mut patch = DynamicTupleStruct::default();
patch.insert(3u32);
patch.insert(4u64);
assert_eq!(3, *patch.field(0).unwrap().downcast_ref::<u32>().unwrap());
assert_eq!(4, *patch.field(1).unwrap().downcast_ref::<u64>().unwrap());
assert_eq!(
3,
*patch.field(0).unwrap().try_downcast_ref::<u32>().unwrap()
);
assert_eq!(
4,
*patch.field(1).unwrap().try_downcast_ref::<u64>().unwrap()
);
foo.apply(&patch);
assert_eq!(3, foo.0);
assert_eq!(4, foo.1);
let mut iter = patch.iter_fields();
assert_eq!(3, *iter.next().unwrap().downcast_ref::<u32>().unwrap());
assert_eq!(4, *iter.next().unwrap().downcast_ref::<u64>().unwrap());
assert_eq!(3, *iter.next().unwrap().try_downcast_ref::<u32>().unwrap());
assert_eq!(4, *iter.next().unwrap().try_downcast_ref::<u64>().unwrap());
}
#[test]
@ -831,7 +896,7 @@ mod tests {
let values: Vec<u32> = foo
.iter_fields()
.map(|value| *value.downcast_ref::<u32>().unwrap())
.map(|value| *value.try_downcast_ref::<u32>().unwrap())
.collect();
assert_eq!(values, vec![1]);
}
@ -863,11 +928,11 @@ mod tests {
// Assert
let expected = MyStruct { foo: 123 };
assert!(expected
.reflect_partial_eq(reflected.as_ref())
.reflect_partial_eq(reflected.as_partial_reflect())
.unwrap_or_default());
let not_expected = MyStruct { foo: 321 };
assert!(!not_expected
.reflect_partial_eq(reflected.as_ref())
.reflect_partial_eq(reflected.as_partial_reflect())
.unwrap_or_default());
}
@ -1314,9 +1379,9 @@ mod tests {
let mut deserializer = Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let dynamic_struct = value.take::<DynamicStruct>().unwrap();
let roundtrip_foo = Foo::from_reflect(value.as_partial_reflect()).unwrap();
assert!(foo.reflect_partial_eq(&dynamic_struct).unwrap());
assert!(foo.reflect_partial_eq(&roundtrip_foo).unwrap());
}
#[test]
@ -2071,7 +2136,7 @@ bevy_reflect::tests::Test {
}
let foo = Foo(123);
let foo: &dyn Reflect = &foo;
let foo: &dyn PartialReflect = &foo;
assert!(foo.reflect_hash().is_some());
assert_eq!(Some(true), foo.reflect_partial_eq(foo));
@ -2092,7 +2157,7 @@ bevy_reflect::tests::Test {
}
let foo = Foo(123);
let foo: &dyn Reflect = &foo;
let foo: &dyn PartialReflect = &foo;
assert!(foo.reflect_hash().is_some());
assert_eq!(Some(true), foo.reflect_partial_eq(foo));
@ -2341,7 +2406,7 @@ bevy_reflect::tests::Test {
}
let mut map = HashMap::new();
map.insert(9, 10);
let mut test_struct = TestStruct {
let mut test_struct: DynamicStruct = TestStruct {
tuple: (0, 1),
list: vec![2, 3, 4],
array: [5, 6, 7],
@ -2350,8 +2415,7 @@ bevy_reflect::tests::Test {
map,
value: 12,
}
.clone_value();
let test_struct = test_struct.downcast_mut::<DynamicStruct>().unwrap();
.clone_dynamic();
// test unknown DynamicStruct
let mut test_unknown_struct = DynamicStruct::default();
@ -2472,7 +2536,7 @@ bevy_reflect::tests::Test {
let mut result = Quat::default();
result.apply(&*dynamic_struct);
result.apply(dynamic_struct.as_partial_reflect());
assert_eq!(result, quat(1.0, 2.0, 3.0, 4.0));
}
@ -2529,7 +2593,7 @@ bevy_reflect::tests::Test {
let mut result = Vec3::default();
result.apply(&*dynamic_struct);
result.apply(dynamic_struct.as_partial_reflect());
assert_eq!(result, vec3(12.0, 3.0, -6.9));
}
@ -2550,13 +2614,16 @@ bevy_reflect::tests::Test {
let mut v = vec3(1.0, 2.0, 3.0);
assert_eq!(
*v.reflect_path("x").unwrap().downcast_ref::<f32>().unwrap(),
*v.reflect_path("x")
.unwrap()
.try_downcast_ref::<f32>()
.unwrap(),
1.0
);
*v.reflect_path_mut("y")
.unwrap()
.downcast_mut::<f32>()
.try_downcast_mut::<f32>()
.unwrap() = 6.0;
assert_eq!(v.y, 6.0);

View file

@ -6,8 +6,8 @@ use bevy_reflect_derive::impl_type_path;
use crate::utility::reflect_hasher;
use crate::{
self as bevy_reflect, ApplyError, FromReflect, MaybeTyped, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
self as bevy_reflect, ApplyError, FromReflect, MaybeTyped, PartialReflect, Reflect,
ReflectKind, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
};
/// A trait used to power [list-like] operations via [reflection].
@ -35,46 +35,46 @@ use crate::{
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, List};
/// use bevy_reflect::{PartialReflect, Reflect, List};
///
/// let foo: &mut dyn List = &mut vec![123_u32, 456_u32, 789_u32];
/// assert_eq!(foo.len(), 3);
///
/// let last_field: Box<dyn Reflect> = foo.pop().unwrap();
/// assert_eq!(last_field.downcast_ref::<u32>(), Some(&789));
/// let last_field: Box<dyn PartialReflect> = foo.pop().unwrap();
/// assert_eq!(last_field.try_downcast_ref::<u32>(), Some(&789));
/// ```
///
/// [list-like]: https://doc.rust-lang.org/book/ch08-01-vectors.html
/// [reflection]: crate
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
pub trait List: Reflect {
pub trait List: PartialReflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn Reflect>;
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Inserts an element at position `index` within the list,
/// shifting all elements after it towards the back of the list.
///
/// # Panics
/// Panics if `index > len`.
fn insert(&mut self, index: usize, element: Box<dyn Reflect>);
fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>);
/// Removes and returns the element at position `index` within the list,
/// shifting all elements before it towards the front of the list.
///
/// # Panics
/// Panics if `index` is out of bounds.
fn remove(&mut self, index: usize) -> Box<dyn Reflect>;
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect>;
/// Appends an element to the _back_ of the list.
fn push(&mut self, value: Box<dyn Reflect>) {
fn push(&mut self, value: Box<dyn PartialReflect>) {
self.insert(self.len(), value);
}
/// Removes the _back_ element from the list and returns it, or [`None`] if it is empty.
fn pop(&mut self) -> Option<Box<dyn Reflect>> {
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
if self.is_empty() {
None
} else {
@ -94,13 +94,13 @@ pub trait List: Reflect {
fn iter(&self) -> ListIter;
/// Drain the elements of this list to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>>;
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the list, producing a [`DynamicList`].
fn clone_dynamic(&self) -> DynamicList {
DynamicList {
represented_type: self.get_represented_type_info(),
values: self.iter().map(Reflect::clone_value).collect(),
values: self.iter().map(PartialReflect::clone_value).collect(),
}
}
}
@ -200,7 +200,7 @@ impl ListInfo {
#[derive(Default)]
pub struct DynamicList {
represented_type: Option<&'static TypeInfo>,
values: Vec<Box<dyn Reflect>>,
values: Vec<Box<dyn PartialReflect>>,
}
impl DynamicList {
@ -223,38 +223,38 @@ impl DynamicList {
}
/// Appends a typed value to the list.
pub fn push<T: Reflect>(&mut self, value: T) {
pub fn push<T: PartialReflect>(&mut self, value: T) {
self.values.push(Box::new(value));
}
/// Appends a [`Reflect`] trait object to the list.
pub fn push_box(&mut self, value: Box<dyn Reflect>) {
pub fn push_box(&mut self, value: Box<dyn PartialReflect>) {
self.values.push(value);
}
}
impl List for DynamicList {
fn get(&self, index: usize) -> Option<&dyn Reflect> {
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
self.values.get(index).map(|value| &**value)
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {
fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>) {
self.values.insert(index, element);
}
fn remove(&mut self, index: usize) -> Box<dyn Reflect> {
fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
self.values.remove(index)
}
fn push(&mut self, value: Box<dyn Reflect>) {
fn push(&mut self, value: Box<dyn PartialReflect>) {
DynamicList::push_box(self, value);
}
fn pop(&mut self) -> Option<Box<dyn Reflect>> {
fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
self.values.pop()
}
@ -266,7 +266,7 @@ impl List for DynamicList {
ListIter::new(self)
}
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.values
}
@ -282,56 +282,47 @@ impl List for DynamicList {
}
}
impl Reflect for DynamicList {
impl PartialReflect for DynamicList {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> {
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_any(&self) -> &dyn Any {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn Reflect) {
fn apply(&mut self, value: &dyn PartialReflect) {
list_apply(self, value);
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
list_try_apply(self, value)
}
#[inline]
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::List
@ -353,7 +344,7 @@ impl Reflect for DynamicList {
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
@ -362,7 +353,7 @@ impl Reflect for DynamicList {
list_hash(self)
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
list_partial_eq(self, value)
}
@ -379,8 +370,6 @@ impl Reflect for DynamicList {
}
impl_type_path!((in bevy_reflect) DynamicList);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicList);
impl Debug for DynamicList {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@ -388,8 +377,8 @@ impl Debug for DynamicList {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicList {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(values: I) -> Self {
impl FromIterator<Box<dyn PartialReflect>> for DynamicList {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect(),
@ -397,17 +386,17 @@ impl FromIterator<Box<dyn Reflect>> for DynamicList {
}
}
impl<T: Reflect> FromIterator<T> for DynamicList {
impl<T: PartialReflect> FromIterator<T> for DynamicList {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|field| Box::new(field).into_reflect())
.map(|field| Box::new(field).into_partial_reflect())
.collect()
}
}
impl IntoIterator for DynamicList {
type Item = Box<dyn Reflect>;
type Item = Box<dyn PartialReflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -416,7 +405,7 @@ impl IntoIterator for DynamicList {
}
impl<'a> IntoIterator for &'a DynamicList {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
type IntoIter = ListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
@ -439,7 +428,7 @@ impl<'a> ListIter<'a> {
}
impl<'a> Iterator for ListIter<'a> {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
@ -478,7 +467,7 @@ pub fn list_hash<L: List>(list: &L) -> Option<u64> {
///
/// This function panics if `b` is not a list.
#[inline]
pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
pub fn list_apply<L: List>(a: &mut L, b: &dyn PartialReflect) {
if let Err(err) = list_try_apply(a, b) {
panic!("{err}");
}
@ -495,7 +484,7 @@ pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a list or if
/// applying elements to each other fails.
#[inline]
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn Reflect) -> Result<(), ApplyError> {
pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::List(list_value) = b.reflect_ref() {
for (i, value) in list_value.iter().enumerate() {
if i < a.len() {
@ -520,11 +509,11 @@ pub fn list_try_apply<L: List>(a: &mut L, b: &dyn Reflect) -> Result<(), ApplyEr
/// Returns true if and only if all of the following are true:
/// - `b` is a list;
/// - `b` is the same length as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn list_partial_eq<L: List>(a: &L, b: &dyn Reflect) -> Option<bool> {
pub fn list_partial_eq<L: List + ?Sized>(a: &L, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::List(list) = b.reflect_ref() else {
return Some(false);
};
@ -583,7 +572,9 @@ mod tests {
list.push(2usize);
let items = list.into_iter();
for (index, item) in items.into_iter().enumerate() {
let value = item.take::<usize>().expect("couldn't downcast to usize");
let value = item
.try_take::<usize>()
.expect("couldn't downcast to usize");
assert_eq!(index, value);
}
}

View file

@ -5,8 +5,8 @@ use bevy_reflect_derive::impl_type_path;
use bevy_utils::{Entry, HashMap};
use crate::{
self as bevy_reflect, ApplyError, MaybeTyped, Reflect, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo, TypePath, TypePathTable,
self as bevy_reflect, ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
};
/// A trait used to power [map-like] operations via [reflection].
@ -17,7 +17,7 @@ use crate::{
///
/// # Hashing
///
/// All keys are expected to return a valid hash value from [`Reflect::reflect_hash`].
/// All keys are expected to return a valid hash value from [`PartialReflect::reflect_hash`].
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding `#[reflect(Hash)]`
/// to the entire struct or enum.
/// This is true even for manual implementors who do not use the hashed value,
@ -26,7 +26,7 @@ use crate::{
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, Map};
/// use bevy_reflect::{PartialReflect, Reflect, Map};
/// use bevy_utils::HashMap;
///
///
@ -34,28 +34,31 @@ use crate::{
/// foo.insert_boxed(Box::new(123_u32), Box::new(true));
/// assert_eq!(foo.len(), 1);
///
/// let field: &dyn Reflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.downcast_ref::<bool>(), Some(&true));
/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.try_downcast_ref::<bool>(), Some(&true));
/// ```
///
/// [map-like]: https://doc.rust-lang.org/book/ch08-03-hash-maps.html
/// [reflection]: crate
pub trait Map: Reflect {
pub trait Map: PartialReflect {
/// Returns a reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect>;
fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect>;
fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect>;
/// Returns the key-value pair at `index` by reference, or `None` if out of bounds.
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)>;
fn get_at(&self, index: usize) -> Option<(&dyn PartialReflect, &dyn PartialReflect)>;
/// Returns the key-value pair at `index` by reference where the value is a mutable reference, or `None` if out of bounds.
fn get_at_mut(&mut self, index: usize) -> Option<(&dyn Reflect, &mut dyn Reflect)>;
fn get_at_mut(
&mut self,
index: usize,
) -> Option<(&dyn PartialReflect, &mut dyn PartialReflect)>;
/// Returns the number of elements in the map.
fn len(&self) -> usize;
@ -69,7 +72,7 @@ pub trait Map: Reflect {
fn iter(&self) -> MapIter;
/// Drain the key-value pairs of this map to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<(Box<dyn Reflect>, Box<dyn Reflect>)>;
fn drain(self: Box<Self>) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>;
/// Clones the map, producing a [`DynamicMap`].
fn clone_dynamic(&self) -> DynamicMap;
@ -80,15 +83,15 @@ pub trait Map: Reflect {
/// If the map did have this key present, the value is updated, and the old value is returned.
fn insert_boxed(
&mut self,
key: Box<dyn Reflect>,
value: Box<dyn Reflect>,
) -> Option<Box<dyn Reflect>>;
key: Box<dyn PartialReflect>,
value: Box<dyn PartialReflect>,
) -> Option<Box<dyn PartialReflect>>;
/// Removes an entry from the map.
///
/// If the map did not have this key present, `None` is returned.
/// If the map did have this key present, the removed value is returned.
fn remove(&mut self, key: &dyn Reflect) -> Option<Box<dyn Reflect>>;
fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>>;
}
/// A container for compile-time map info.
@ -246,7 +249,7 @@ macro_rules! hash_error {
#[derive(Default)]
pub struct DynamicMap {
represented_type: Option<&'static TypeInfo>,
values: Vec<(Box<dyn Reflect>, Box<dyn Reflect>)>,
values: Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>,
indices: HashMap<u64, usize>,
}
@ -271,32 +274,35 @@ impl DynamicMap {
}
/// Inserts a typed key-value pair into the map.
pub fn insert<K: Reflect, V: Reflect>(&mut self, key: K, value: V) {
pub fn insert<K: PartialReflect, V: PartialReflect>(&mut self, key: K, value: V) {
self.insert_boxed(Box::new(key), Box::new(value));
}
}
impl Map for DynamicMap {
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
self.indices
.get(&key.reflect_hash().expect(hash_error!(key)))
.map(|index| &*self.values.get(*index).unwrap().1)
}
fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect> {
fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect> {
self.indices
.get(&key.reflect_hash().expect(hash_error!(key)))
.cloned()
.map(move |index| &mut *self.values.get_mut(index).unwrap().1)
}
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)> {
fn get_at(&self, index: usize) -> Option<(&dyn PartialReflect, &dyn PartialReflect)> {
self.values
.get(index)
.map(|(key, value)| (&**key, &**value))
}
fn get_at_mut(&mut self, index: usize) -> Option<(&dyn Reflect, &mut dyn Reflect)> {
fn get_at_mut(
&mut self,
index: usize,
) -> Option<(&dyn PartialReflect, &mut dyn PartialReflect)> {
self.values
.get_mut(index)
.map(|(key, value)| (&**key, &mut **value))
@ -310,7 +316,7 @@ impl Map for DynamicMap {
MapIter::new(self)
}
fn drain(self: Box<Self>) -> Vec<(Box<dyn Reflect>, Box<dyn Reflect>)> {
fn drain(self: Box<Self>) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> {
self.values
}
@ -328,9 +334,9 @@ impl Map for DynamicMap {
fn insert_boxed(
&mut self,
key: Box<dyn Reflect>,
mut value: Box<dyn Reflect>,
) -> Option<Box<dyn Reflect>> {
key: Box<dyn PartialReflect>,
mut value: Box<dyn PartialReflect>,
) -> Option<Box<dyn PartialReflect>> {
match self
.indices
.entry(key.reflect_hash().expect(hash_error!(key)))
@ -348,7 +354,7 @@ impl Map for DynamicMap {
}
}
fn remove(&mut self, key: &dyn Reflect) -> Option<Box<dyn Reflect>> {
fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>> {
let index = self
.indices
.remove(&key.reflect_hash().expect(hash_error!(key)))?;
@ -357,52 +363,47 @@ impl Map for DynamicMap {
}
}
impl Reflect for DynamicMap {
impl PartialReflect for DynamicMap {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn apply(&mut self, value: &dyn Reflect) {
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
map_apply(self, value);
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
map_try_apply(self, value)
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Map
}
@ -419,11 +420,11 @@ impl Reflect for DynamicMap {
ReflectOwned::Map(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
map_partial_eq(self, value)
}
@ -440,8 +441,6 @@ impl Reflect for DynamicMap {
}
impl_type_path!((in bevy_reflect) DynamicMap);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicMap);
impl Debug for DynamicMap {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@ -464,7 +463,7 @@ impl<'a> MapIter<'a> {
}
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a dyn Reflect, &'a dyn Reflect);
type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
fn next(&mut self) -> Option<Self::Item> {
let value = self.map.get_at(self.index);
@ -478,8 +477,10 @@ impl<'a> Iterator for MapIter<'a> {
}
}
impl FromIterator<(Box<dyn Reflect>, Box<dyn Reflect>)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (Box<dyn Reflect>, Box<dyn Reflect>)>>(items: I) -> Self {
impl FromIterator<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>)>>(
items: I,
) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert_boxed(key, value);
@ -499,7 +500,7 @@ impl<K: Reflect, V: Reflect> FromIterator<(K, V)> for DynamicMap {
}
impl IntoIterator for DynamicMap {
type Item = (Box<dyn Reflect>, Box<dyn Reflect>);
type Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>);
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -508,7 +509,7 @@ impl IntoIterator for DynamicMap {
}
impl<'a> IntoIterator for &'a DynamicMap {
type Item = (&'a dyn Reflect, &'a dyn Reflect);
type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
type IntoIter = MapIter<'a>;
fn into_iter(self) -> Self::IntoIter {
@ -518,17 +519,17 @@ impl<'a> IntoIterator for &'a DynamicMap {
impl<'a> ExactSizeIterator for MapIter<'a> {}
/// Compares a [`Map`] with a [`Reflect`] value.
/// Compares a [`Map`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a map;
/// - `b` is the same length as `a`;
/// - For each key-value pair in `a`, `b` contains a value for the given key,
/// and [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two values.
/// and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn map_partial_eq<M: Map>(a: &M, b: &dyn Reflect) -> Option<bool> {
pub fn map_partial_eq<M: Map + ?Sized>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Map(map) = b.reflect_ref() else {
return Some(false);
};
@ -585,7 +586,7 @@ pub fn map_debug(dyn_map: &dyn Map, f: &mut Formatter<'_>) -> std::fmt::Result {
///
/// This function panics if `b` is not a reflected map.
#[inline]
pub fn map_apply<M: Map>(a: &mut M, b: &dyn Reflect) {
pub fn map_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) {
if let Err(err) = map_try_apply(a, b) {
panic!("{err}");
}
@ -601,7 +602,7 @@ pub fn map_apply<M: Map>(a: &mut M, b: &dyn Reflect) {
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected map or if
/// applying elements to each other fails.
#[inline]
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn Reflect) -> Result<(), ApplyError> {
pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::Map(map_value) = b.reflect_ref() {
for (key, b_value) in map_value.iter() {
if let Some(a_value) = a.get_mut(key) {
@ -623,7 +624,6 @@ pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn Reflect) -> Result<(), ApplyErro
mod tests {
use super::DynamicMap;
use super::Map;
use crate::reflect::Reflect;
#[test]
fn test_into_iter() {
@ -635,10 +635,13 @@ mod tests {
map.insert(2usize, expected[2].to_string());
for (index, item) in map.into_iter().enumerate() {
let key = item.0.take::<usize>().expect("couldn't downcast to usize");
let key = item
.0
.try_take::<usize>()
.expect("couldn't downcast to usize");
let value = item
.1
.take::<String>()
.try_take::<String>()
.expect("couldn't downcast to String");
assert_eq!(index, key);
assert_eq!(expected[index], value);
@ -655,16 +658,16 @@ mod tests {
let (key_r, value_r) = map.get_at(1).expect("Item wasn't found");
let value = value_r
.downcast_ref::<String>()
.try_downcast_ref::<String>()
.expect("Couldn't downcast to String");
let key = key_r
.downcast_ref::<usize>()
.try_downcast_ref::<usize>()
.expect("Couldn't downcast to usize");
assert_eq!(key, &1usize);
assert_eq!(value, &values[2].to_owned());
assert!(map.get_at(2).is_none());
map.remove(&1usize as &dyn Reflect);
map.remove(&1usize);
assert!(map.get_at(1).is_none());
}
@ -678,10 +681,10 @@ mod tests {
let (key_r, value_r) = map.get_at_mut(1).expect("Item wasn't found");
let value = value_r
.downcast_mut::<String>()
.try_downcast_mut::<String>()
.expect("Couldn't downcast to String");
let key = key_r
.downcast_ref::<usize>()
.try_downcast_ref::<usize>()
.expect("Couldn't downcast to usize");
assert_eq!(key, &1usize);
assert_eq!(value, &mut values[2].to_owned());
@ -689,9 +692,9 @@ mod tests {
value.clone_from(&values[0].to_owned());
assert_eq!(
map.get(&1usize as &dyn Reflect)
map.get(&1usize)
.expect("Item wasn't found")
.downcast_ref::<String>()
.try_downcast_ref::<String>()
.expect("Couldn't downcast to String"),
&values[0].to_owned()
);

View file

@ -3,14 +3,14 @@
use std::{borrow::Cow, fmt};
use super::error::AccessErrorKind;
use crate::{AccessError, Reflect, ReflectKind, ReflectMut, ReflectRef, VariantType};
use crate::{AccessError, PartialReflect, ReflectKind, ReflectMut, ReflectRef, VariantType};
type InnerResult<T> = Result<T, AccessErrorKind>;
/// A singular element access within a path.
/// Multiple accesses can be combined into a [`ParsedPath`](super::ParsedPath).
///
/// Can be applied to a [`dyn Reflect`](Reflect) to get a reference to the targeted element.
/// Can be applied to a [`dyn Reflect`](crate::Reflect) to get a reference to the targeted element.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Access<'a> {
/// A name-based field access on a struct.
@ -51,15 +51,18 @@ impl<'a> Access<'a> {
pub(super) fn element<'r>(
&self,
base: &'r dyn Reflect,
base: &'r dyn PartialReflect,
offset: Option<usize>,
) -> Result<&'r dyn Reflect, AccessError<'a>> {
) -> Result<&'r dyn PartialReflect, AccessError<'a>> {
self.element_inner(base)
.and_then(|opt| opt.ok_or(AccessErrorKind::MissingField(base.reflect_kind())))
.map_err(|err| err.with_access(self.clone(), offset))
}
fn element_inner<'r>(&self, base: &'r dyn Reflect) -> InnerResult<Option<&'r dyn Reflect>> {
fn element_inner<'r>(
&self,
base: &'r dyn PartialReflect,
) -> InnerResult<Option<&'r dyn PartialReflect>> {
use ReflectRef::*;
let invalid_variant =
@ -105,9 +108,9 @@ impl<'a> Access<'a> {
pub(super) fn element_mut<'r>(
&self,
base: &'r mut dyn Reflect,
base: &'r mut dyn PartialReflect,
offset: Option<usize>,
) -> Result<&'r mut dyn Reflect, AccessError<'a>> {
) -> Result<&'r mut dyn PartialReflect, AccessError<'a>> {
let kind = base.reflect_kind();
self.element_inner_mut(base)
@ -117,8 +120,8 @@ impl<'a> Access<'a> {
fn element_inner_mut<'r>(
&self,
base: &'r mut dyn Reflect,
) -> InnerResult<Option<&'r mut dyn Reflect>> {
base: &'r mut dyn PartialReflect,
) -> InnerResult<Option<&'r mut dyn PartialReflect>> {
use ReflectMut::*;
let invalid_variant =

View file

@ -8,7 +8,7 @@ mod parse;
pub use parse::ParseError;
use parse::PathParser;
use crate::Reflect;
use crate::{PartialReflect, Reflect};
use std::fmt;
use thiserror::Error;
@ -49,19 +49,22 @@ pub trait ReflectPath<'a>: Sized {
///
/// See [`GetPath::reflect_path`] for more details,
/// see [`element`](Self::element) if you want a typed return value.
fn reflect_element(self, root: &dyn Reflect) -> PathResult<'a, &dyn Reflect>;
fn reflect_element(self, root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect>;
/// Gets a mutable reference to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::reflect_path_mut`] for more details.
fn reflect_element_mut(self, root: &mut dyn Reflect) -> PathResult<'a, &mut dyn Reflect>;
fn reflect_element_mut(
self,
root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect>;
/// Gets a `&T` to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::path`] for more details.
fn element<T: Reflect>(self, root: &dyn Reflect) -> PathResult<'a, &T> {
fn element<T: Reflect>(self, root: &dyn PartialReflect) -> PathResult<'a, &T> {
self.reflect_element(root).and_then(|p| {
p.downcast_ref::<T>()
p.try_downcast_ref::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
@ -69,22 +72,25 @@ pub trait ReflectPath<'a>: Sized {
/// Gets a `&mut T` to the specified element on the given [`Reflect`] object.
///
/// See [`GetPath::path_mut`] for more details.
fn element_mut<T: Reflect>(self, root: &mut dyn Reflect) -> PathResult<'a, &mut T> {
fn element_mut<T: Reflect>(self, root: &mut dyn PartialReflect) -> PathResult<'a, &mut T> {
self.reflect_element_mut(root).and_then(|p| {
p.downcast_mut::<T>()
p.try_downcast_mut::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
}
impl<'a> ReflectPath<'a> for &'a str {
fn reflect_element(self, mut root: &dyn Reflect) -> PathResult<'a, &dyn Reflect> {
fn reflect_element(self, mut root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect> {
for (access, offset) in PathParser::new(self) {
let a = access?;
root = a.element(root, Some(offset))?;
}
Ok(root)
}
fn reflect_element_mut(self, mut root: &mut dyn Reflect) -> PathResult<'a, &mut dyn Reflect> {
fn reflect_element_mut(
self,
mut root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect> {
for (access, offset) in PathParser::new(self) {
root = access?.element_mut(root, Some(offset))?;
}
@ -234,13 +240,13 @@ impl<'a> ReflectPath<'a> for &'a str {
message = "`{Self}` does not provide a reflection path",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetPath: Reflect {
pub trait GetPath: PartialReflect {
/// Returns a reference to the value specified by `path`.
///
/// To retrieve a statically typed reference, use
/// [`path`][GetPath::path].
fn reflect_path<'p>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &dyn Reflect> {
path.reflect_element(self.as_reflect())
fn reflect_path<'p>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &dyn PartialReflect> {
path.reflect_element(self.as_partial_reflect())
}
/// Returns a mutable reference to the value specified by `path`.
@ -250,8 +256,8 @@ pub trait GetPath: Reflect {
fn reflect_path_mut<'p>(
&mut self,
path: impl ReflectPath<'p>,
) -> PathResult<'p, &mut dyn Reflect> {
path.reflect_element_mut(self.as_reflect_mut())
) -> PathResult<'p, &mut dyn PartialReflect> {
path.reflect_element_mut(self.as_partial_reflect_mut())
}
/// Returns a statically typed reference to the value specified by `path`.
@ -262,7 +268,7 @@ pub trait GetPath: Reflect {
///
/// [`DynamicStruct`]: crate::DynamicStruct
fn path<'p, T: Reflect>(&self, path: impl ReflectPath<'p>) -> PathResult<'p, &T> {
path.element(self.as_reflect())
path.element(self.as_partial_reflect())
}
/// Returns a statically typed mutable reference to the value specified by `path`.
@ -273,7 +279,7 @@ pub trait GetPath: Reflect {
///
/// [`DynamicStruct`]: crate::DynamicStruct
fn path_mut<'p, T: Reflect>(&mut self, path: impl ReflectPath<'p>) -> PathResult<'p, &mut T> {
path.element_mut(self.as_reflect_mut())
path.element_mut(self.as_partial_reflect_mut())
}
}
@ -427,13 +433,16 @@ impl ParsedPath {
}
}
impl<'a> ReflectPath<'a> for &'a ParsedPath {
fn reflect_element(self, mut root: &dyn Reflect) -> PathResult<'a, &dyn Reflect> {
fn reflect_element(self, mut root: &dyn PartialReflect) -> PathResult<'a, &dyn PartialReflect> {
for OffsetAccess { access, offset } in &self.0 {
root = access.element(root, *offset)?;
}
Ok(root)
}
fn reflect_element_mut(self, mut root: &mut dyn Reflect) -> PathResult<'a, &mut dyn Reflect> {
fn reflect_element_mut(
self,
mut root: &mut dyn PartialReflect,
) -> PathResult<'a, &mut dyn PartialReflect> {
for OffsetAccess { access, offset } in &self.0 {
root = access.element_mut(root, *offset)?;
}

View file

@ -54,7 +54,7 @@ macro_rules! impl_reflect_enum {
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectRef`] is obtained via [`Reflect::reflect_ref`].
/// A [`ReflectRef`] is obtained via [`PartialReflect::reflect_ref`].
pub enum ReflectRef<'a> {
Struct(&'a dyn Struct),
TupleStruct(&'a dyn TupleStruct),
@ -64,7 +64,7 @@ pub enum ReflectRef<'a> {
Map(&'a dyn Map),
Set(&'a dyn Set),
Enum(&'a dyn Enum),
Value(&'a dyn Reflect),
Value(&'a dyn PartialReflect),
}
impl_reflect_enum!(ReflectRef<'_>);
@ -73,7 +73,7 @@ impl_reflect_enum!(ReflectRef<'_>);
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectMut`] is obtained via [`Reflect::reflect_mut`].
/// A [`ReflectMut`] is obtained via [`PartialReflect::reflect_mut`].
pub enum ReflectMut<'a> {
Struct(&'a mut dyn Struct),
TupleStruct(&'a mut dyn TupleStruct),
@ -83,7 +83,7 @@ pub enum ReflectMut<'a> {
Map(&'a mut dyn Map),
Set(&'a mut dyn Set),
Enum(&'a mut dyn Enum),
Value(&'a mut dyn Reflect),
Value(&'a mut dyn PartialReflect),
}
impl_reflect_enum!(ReflectMut<'_>);
@ -92,7 +92,7 @@ impl_reflect_enum!(ReflectMut<'_>);
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A [`ReflectOwned`] is obtained via [`Reflect::reflect_owned`].
/// A [`ReflectOwned`] is obtained via [`PartialReflect::reflect_owned`].
pub enum ReflectOwned {
Struct(Box<dyn Struct>),
TupleStruct(Box<dyn TupleStruct>),
@ -102,11 +102,11 @@ pub enum ReflectOwned {
Map(Box<dyn Map>),
Set(Box<dyn Set>),
Enum(Box<dyn Enum>),
Value(Box<dyn Reflect>),
Value(Box<dyn PartialReflect>),
}
impl_reflect_enum!(ReflectOwned);
/// A enumeration of all error outcomes that might happen when running [`try_apply`](Reflect::try_apply).
/// A enumeration of all error outcomes that might happen when running [`try_apply`](PartialReflect::try_apply).
#[derive(Error, Debug)]
pub enum ApplyError {
#[error("attempted to apply `{from_kind}` to `{to_kind}`")]
@ -144,7 +144,7 @@ pub enum ApplyError {
/// A zero-sized enumuration of the "kinds" of a reflected type.
///
/// A [`ReflectKind`] is obtained via [`Reflect::reflect_kind`],
/// A [`ReflectKind`] is obtained via [`PartialReflect::reflect_kind`],
/// or via [`ReflectRef::kind`],[`ReflectMut::kind`] or [`ReflectOwned::kind`].
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ReflectKind {
@ -175,22 +175,29 @@ impl std::fmt::Display for ReflectKind {
}
}
/// The core trait of [`bevy_reflect`], used for accessing and modifying data dynamically.
/// The foundational trait of [`bevy_reflect`], used for accessing and modifying data dynamically.
///
/// It's recommended to use the [derive macro] rather than manually implementing this trait.
/// Doing so will automatically implement many other useful traits for reflection,
/// This is a supertrait of [`Reflect`],
/// meaning any type which implements `Reflect` implements `PartialReflect` by definition.
///
/// It's recommended to use [the derive macro for `Reflect`] rather than manually implementing this trait.
/// Doing so will automatically implement this trait as well as many other useful traits for reflection,
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
///
/// See the [crate-level documentation] to see how this trait and its subtraits can be used.
///
/// [`bevy_reflect`]: crate
/// [derive macro]: bevy_reflect_derive::Reflect
/// [the derive macro for `Reflect`]: bevy_reflect_derive::Reflect
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` can not be reflected",
message = "`{Self}` does not implement `PartialReflect` so cannot be introspected",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait Reflect: DynamicTypePath + Any + Send + Sync {
pub trait PartialReflect: DynamicTypePath + Send + Sync
where
// NB: we don't use `Self: Any` since for downcasting, `Reflect` should be used.
Self: 'static,
{
/// Returns the [`TypeInfo`] of the type _represented_ by this value.
///
/// For most types, this will simply return their own `TypeInfo`.
@ -208,27 +215,39 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>;
/// Returns the value as a [`Box<dyn Any>`][std::any::Any].
fn into_any(self: Box<Self>) -> Box<dyn Any>;
/// Returns the value as a [`&dyn Any`][std::any::Any].
fn as_any(&self) -> &dyn Any;
/// Returns the value as a [`&mut dyn Any`][std::any::Any].
fn as_any_mut(&mut self) -> &mut dyn Any;
/// Casts this type to a boxed reflected value.
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect>;
/// Casts this type to a boxed, reflected value.
///
/// This is useful for coercing trait objects.
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect>;
/// Casts this type to a reflected value.
fn as_reflect(&self) -> &dyn Reflect;
///
/// This is useful for coercing trait objects.
fn as_partial_reflect(&self) -> &dyn PartialReflect;
/// Casts this type to a mutable reflected value.
fn as_reflect_mut(&mut self) -> &mut dyn Reflect;
/// Casts this type to a mutable, reflected value.
///
/// This is useful for coercing trait objects.
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect;
/// Attempts to cast this type to a boxed, [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>;
/// Attempts to cast this type to a [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_as_reflect(&self) -> Option<&dyn Reflect>;
/// Attempts to cast this type to a mutable, [fully-reflected] value.
///
/// [fully-reflected]: Reflect
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect>;
/// Applies a reflected value to this value.
///
/// If a type implements a subtrait of `Reflect`, then the semantics of this
/// If a type implements an [introspection subtrait], then the semantics of this
/// method are as follows:
/// - If `T` is a [`Struct`], then the value of each named field of `value` is
/// applied to the corresponding named field of `self`. Fields which are
@ -255,6 +274,7 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
/// or none of the above depending on the kind of type. For lists and maps, use the
/// [`list_apply`] and [`map_apply`] helper functions when implementing this method.
///
/// [introspection subtrait]: crate#the-introspection-subtraits
/// [`list_apply`]: crate::list_apply
/// [`map_apply`]: crate::map_apply
///
@ -266,26 +286,20 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
/// - If `T` is any complex type and the corresponding fields or elements of
/// `self` and `value` are not of the same type.
/// - If `T` is a value type and `self` cannot be downcast to `T`
fn apply(&mut self, value: &dyn Reflect) {
Reflect::try_apply(self, value).unwrap();
fn apply(&mut self, value: &dyn PartialReflect) {
PartialReflect::try_apply(self, value).unwrap();
}
/// Tries to [`apply`](Reflect::apply) a reflected value to this value.
/// Tries to [`apply`](PartialReflect::apply) a reflected value to this value.
///
/// Functions the same as the [`apply`](Reflect::apply) function but returns an error instead of
/// Functions the same as the [`apply`](PartialReflect::apply) function but returns an error instead of
/// panicking.
///
/// # Handling Errors
///
/// This function may leave `self` in a partially mutated state if a error was encountered on the way.
/// consider maintaining a cloned instance of this data you can switch to if a error is encountered.
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError>;
/// Performs a type-checked assignment of a reflected value to this value.
///
/// If `value` does not contain a value of type `T`, returns an `Err`
/// containing the trait object.
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError>;
/// Returns a zero-sized enumeration of "kinds" of type.
///
@ -316,7 +330,7 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
/// or [`Enum::clone_dynamic`], respectively.
/// Implementors of other `Reflect` subtraits (e.g. [`List`], [`Map`]) should
/// use those subtraits' respective `clone_dynamic` methods.
fn clone_value(&self) -> Box<dyn Reflect>;
fn clone_value(&self) -> Box<dyn PartialReflect>;
/// Returns a hash of the value (which includes the type).
///
@ -328,7 +342,7 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
/// Returns a "partial equality" comparison result.
///
/// If the underlying type does not support equality testing, returns `None`.
fn reflect_partial_eq(&self, _value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
None
}
@ -376,29 +390,116 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync {
}
}
impl Debug for dyn Reflect {
/// A core trait of [`bevy_reflect`], used for downcasting to concrete types.
///
/// This is a subtrait of [`PartialReflect`],
/// meaning any type which implements `Reflect` implements `PartialReflect` by definition.
///
/// It's recommended to use [the derive macro] rather than manually implementing this trait.
/// Doing so will automatically implement this trait, [`PartialReflect`], and many other useful traits for reflection,
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
///
/// See the [crate-level documentation] to see how this trait can be used.
///
/// [`bevy_reflect`]: crate
/// [the derive macro]: bevy_reflect_derive::Reflect
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Reflect` so cannot be fully reflected",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait Reflect: PartialReflect + Any {
/// Returns the value as a [`Box<dyn Any>`][std::any::Any].
fn into_any(self: Box<Self>) -> Box<dyn Any>;
/// Returns the value as a [`&dyn Any`][std::any::Any].
fn as_any(&self) -> &dyn Any;
/// Returns the value as a [`&mut dyn Any`][std::any::Any].
fn as_any_mut(&mut self) -> &mut dyn Any;
/// Casts this type to a boxed, fully-reflected value.
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect>;
/// Casts this type to a fully-reflected value.
fn as_reflect(&self) -> &dyn Reflect;
/// Casts this type to a mutable, fully-reflected value.
fn as_reflect_mut(&mut self) -> &mut dyn Reflect;
/// Performs a type-checked assignment of a reflected value to this value.
///
/// If `value` does not contain a value of type `T`, returns an `Err`
/// containing the trait object.
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
}
impl dyn PartialReflect {
/// Returns `true` if the underlying value represents a value of type `T`, or `false`
/// otherwise.
///
/// Read `is` for more information on underlying values and represented types.
#[inline]
pub fn represents<T: Reflect + TypePath>(&self) -> bool {
self.get_represented_type_info()
.map(|t| t.type_path() == T::type_path())
.unwrap_or(false)
}
/// Downcasts the value to type `T`, consuming the trait object.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns `Err(self)`.
pub fn try_downcast<T: Reflect>(
self: Box<dyn PartialReflect>,
) -> Result<Box<T>, Box<dyn PartialReflect>> {
self.try_into_reflect()?
.downcast()
.map_err(PartialReflect::into_partial_reflect)
}
/// Downcasts the value to type `T`, unboxing and consuming the trait object.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns `Err(self)`.
pub fn try_take<T: Reflect>(
self: Box<dyn PartialReflect>,
) -> Result<T, Box<dyn PartialReflect>> {
self.try_downcast().map(|value| *value)
}
/// Downcasts the value to type `T` by reference.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns [`None`].
pub fn try_downcast_ref<T: Reflect>(&self) -> Option<&T> {
self.try_as_reflect()?.downcast_ref()
}
/// Downcasts the value to type `T` by mutable reference.
///
/// If the underlying value does not implement [`Reflect`]
/// or is not of type `T`, returns [`None`].
pub fn try_downcast_mut<T: Reflect>(&mut self) -> Option<&mut T> {
self.try_as_reflect_mut()?.downcast_mut()
}
}
impl Debug for dyn PartialReflect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.debug(f)
}
}
impl Typed for dyn Reflect {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
}
}
// The following implementation never actually shadows the concrete TypePath implementation.
// See this playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=589064053f27bc100d90da89c6a860aa).
impl TypePath for dyn Reflect {
// See the comment on `dyn Reflect`'s `TypePath` implementation.
impl TypePath for dyn PartialReflect {
fn type_path() -> &'static str {
"dyn bevy_reflect::Reflect"
"dyn bevy_reflect::PartialReflect"
}
fn short_type_path() -> &'static str {
"dyn Reflect"
"dyn PartialReflect"
}
}
@ -422,17 +523,6 @@ impl dyn Reflect {
self.downcast::<T>().map(|value| *value)
}
/// Returns `true` if the underlying value represents a value of type `T`, or `false`
/// otherwise.
///
/// Read `is` for more information on underlying values and represented types.
#[inline]
pub fn represents<T: Reflect + TypePath>(&self) -> bool {
self.get_represented_type_info()
.map(|t| t.type_path() == T::type_path())
.unwrap_or(false)
}
/// Returns `true` if the underlying value is of type `T`, or `false`
/// otherwise.
///
@ -464,3 +554,68 @@ impl dyn Reflect {
self.as_any_mut().downcast_mut::<T>()
}
}
impl Debug for dyn Reflect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.debug(f)
}
}
impl Typed for dyn Reflect {
fn type_info() -> &'static TypeInfo {
static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new();
CELL.get_or_set(|| TypeInfo::Value(ValueInfo::new::<Self>()))
}
}
// The following implementation never actually shadows the concrete `TypePath` implementation.
// See this playground (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=589064053f27bc100d90da89c6a860aa).
impl TypePath for dyn Reflect {
fn type_path() -> &'static str {
"dyn bevy_reflect::Reflect"
}
fn short_type_path() -> &'static str {
"dyn Reflect"
}
}
macro_rules! impl_full_reflect {
($(<$($id:ident),* $(,)?>)? for $ty:ty $(where $($tt:tt)*)?) => {
impl $(<$($id),*>)? $crate::Reflect for $ty $(where $($tt)*)? {
fn into_any(self: Box<Self>) -> Box<dyn ::std::any::Any> {
self
}
fn as_any(&self) -> &dyn ::std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any {
self
}
fn into_reflect(self: Box<Self>) -> Box<dyn $crate::Reflect> {
self
}
fn as_reflect(&self) -> &dyn $crate::Reflect {
self
}
fn as_reflect_mut(&mut self) -> &mut dyn $crate::Reflect {
self
}
fn set(
&mut self,
value: Box<dyn $crate::Reflect>,
) -> Result<(), Box<dyn $crate::Reflect>> {
*self = <dyn $crate::Reflect>::take(value)?;
Ok(())
}
}
};
}
pub(crate) use impl_full_reflect;

View file

@ -2,8 +2,9 @@ use crate::serde::SerializationData;
use crate::{
ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct,
DynamicTuple, DynamicTupleStruct, DynamicVariant, EnumInfo, ListInfo, Map, MapInfo, NamedField,
Reflect, ReflectDeserialize, Set, SetInfo, StructInfo, StructVariantInfo, TupleInfo,
TupleStructInfo, TupleVariantInfo, TypeInfo, TypeRegistration, TypeRegistry, VariantInfo,
PartialReflect, Reflect, ReflectDeserialize, Set, SetInfo, StructInfo, StructVariantInfo,
TupleInfo, TupleStructInfo, TupleVariantInfo, TypeInfo, TypeRegistration, TypeRegistry,
VariantInfo,
};
use erased_serde::Deserializer;
use serde::de::{
@ -339,21 +340,21 @@ impl<'a, 'de> DeserializeSeed<'de> for TypeRegistrationDeserializer<'a> {
/// let mut deserializer = ron::Deserializer::from_str(input).unwrap();
/// let reflect_deserializer = ReflectDeserializer::new(&registry);
///
/// let output: Box<dyn Reflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not a value type and does not register `ReflectDeserialize`,
/// // we know that its deserialized representation will be a `DynamicStruct`.
/// assert!(output.is::<DynamicStruct>());
/// assert!(output.represents::<MyStruct>());
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
///
/// // We can convert back to `MyStruct` using `FromReflect`.
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(&*output).unwrap();
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(output.as_partial_reflect()).unwrap();
/// assert_eq!(value, MyStruct { value: 123 });
///
/// // We can also do this dynamically with `ReflectFromReflect`.
/// let type_id = output.get_represented_type_info().unwrap().type_id();
/// let reflect_from_reflect = registry.get_type_data::<ReflectFromReflect>(type_id).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(&*output).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(output.as_partial_reflect()).unwrap();
/// assert!(value.is::<MyStruct>());
/// assert_eq!(value.take::<MyStruct>().unwrap(), MyStruct { value: 123 });
/// ```
@ -378,7 +379,7 @@ impl<'a> ReflectDeserializer<'a> {
}
impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
type Value = Box<dyn Reflect>;
type Value = Box<dyn PartialReflect>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
@ -389,7 +390,7 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
}
impl<'a, 'de> Visitor<'de> for UntypedReflectDeserializerVisitor<'a> {
type Value = Box<dyn Reflect>;
type Value = Box<dyn PartialReflect>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter
@ -472,21 +473,21 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
/// let mut deserializer = ron::Deserializer::from_str(input).unwrap();
/// let reflect_deserializer = TypedReflectDeserializer::new(registration, &registry);
///
/// let output: Box<dyn Reflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
/// let output: Box<dyn PartialReflect> = reflect_deserializer.deserialize(&mut deserializer).unwrap();
///
/// // Since `MyStruct` is not a value type and does not register `ReflectDeserialize`,
/// // we know that its deserialized representation will be a `DynamicStruct`.
/// assert!(output.is::<DynamicStruct>());
/// assert!(output.represents::<MyStruct>());
/// // we know that its deserialized value will be a `DynamicStruct`,
/// // although it will represent `MyStruct`.
/// assert!(output.as_partial_reflect().represents::<MyStruct>());
///
/// // We can convert back to `MyStruct` using `FromReflect`.
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(&*output).unwrap();
/// let value: MyStruct = <MyStruct as FromReflect>::from_reflect(output.as_partial_reflect()).unwrap();
/// assert_eq!(value, MyStruct { value: 123 });
///
/// // We can also do this dynamically with `ReflectFromReflect`.
/// let type_id = output.get_represented_type_info().unwrap().type_id();
/// let reflect_from_reflect = registry.get_type_data::<ReflectFromReflect>(type_id).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(&*output).unwrap();
/// let value: Box<dyn Reflect> = reflect_from_reflect.from_reflect(output.as_partial_reflect()).unwrap();
/// assert!(value.is::<MyStruct>());
/// assert_eq!(value.take::<MyStruct>().unwrap(), MyStruct { value: 123 });
/// ```
@ -514,7 +515,7 @@ impl<'a> TypedReflectDeserializer<'a> {
}
impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
type Value = Box<dyn Reflect>;
type Value = Box<dyn PartialReflect>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
@ -525,7 +526,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
// Handle both Value case and types that have a custom `ReflectDeserialize`
if let Some(deserialize_reflect) = self.registration.data::<ReflectDeserialize>() {
let value = deserialize_reflect.deserialize(deserializer)?;
return Ok(value);
return Ok(value.into_partial_reflect());
}
match self.registration.type_info() {
@ -1107,7 +1108,10 @@ where
let Some(field) = info.field_at(*skipped_index) else {
continue;
};
dynamic_struct.insert_boxed(field.name(), skipped_field.generate_default());
dynamic_struct.insert_boxed(
field.name(),
skipped_field.generate_default().into_partial_reflect(),
);
}
}
@ -1137,7 +1141,7 @@ where
for index in 0..len {
if let Some(value) = serialization_data.and_then(|data| data.generate_default(index)) {
tuple.insert_boxed(value);
tuple.insert_boxed(value.into_partial_reflect());
continue;
}
@ -1182,7 +1186,7 @@ where
.unwrap_or_default()
{
if let Some(value) = serialization_data.unwrap().generate_default(index) {
dynamic_struct.insert_boxed(name, value);
dynamic_struct.insert_boxed(name, value.into_partial_reflect());
}
continue;
}
@ -1224,7 +1228,9 @@ mod tests {
use crate as bevy_reflect;
use crate::serde::{ReflectDeserializer, ReflectSerializer, TypedReflectDeserializer};
use crate::{DynamicEnum, FromReflect, Reflect, ReflectDeserialize, TypeRegistry};
use crate::{
DynamicEnum, FromReflect, PartialReflect, Reflect, ReflectDeserialize, TypeRegistry,
};
#[derive(Reflect, Debug, PartialEq)]
struct MyStruct {
@ -1445,7 +1451,7 @@ mod tests {
.deserialize(&mut ron_deserializer)
.unwrap();
let output = dynamic_output
.take::<f32>()
.try_take::<f32>()
.expect("underlying type should be f32");
assert_eq!(1.23, output);
}
@ -1472,7 +1478,9 @@ mod tests {
.deserialize(&mut ron_deserializer)
.unwrap();
let output = <Foo as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
let output =
<Foo as FromReflect>::from_reflect(dynamic_output.as_ref().as_partial_reflect())
.unwrap();
assert_eq!(expected, output);
}
@ -1585,7 +1593,9 @@ mod tests {
let output = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let expected = DynamicEnum::from(MyEnum::Tuple(1.23, 3.21));
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
assert!(expected
.reflect_partial_eq(output.as_partial_reflect())
.unwrap());
// === Struct Variant === //
let input = r#"{
@ -1600,7 +1610,9 @@ mod tests {
let expected = DynamicEnum::from(MyEnum::Struct {
value: String::from("I <3 Enums"),
});
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
assert!(expected
.reflect_partial_eq(output.as_partial_reflect())
.unwrap());
}
// Regression test for https://github.com/bevyengine/bevy/issues/12462
@ -1616,7 +1628,7 @@ mod tests {
let reflect_deserializer = ReflectDeserializer::new(&registry);
let input2 = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let serializer2 = ReflectSerializer::new(&*input2, &registry);
let serializer2 = ReflectSerializer::new(input2.as_partial_reflect(), &registry);
let serialized2 = ron::ser::to_string(&serializer2).unwrap();
assert_eq!(serialized1, serialized2);

View file

@ -8,7 +8,7 @@ pub use type_data::*;
#[cfg(test)]
mod tests {
use crate::{self as bevy_reflect, DynamicTupleStruct, Struct};
use crate::{self as bevy_reflect, DynamicTupleStruct, PartialReflect, Struct};
use crate::{
serde::{ReflectDeserializer, ReflectSerializer},
type_registry::TypeRegistry,
@ -53,8 +53,7 @@ mod tests {
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let deserialized = value.take::<DynamicStruct>().unwrap();
let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let mut expected = DynamicStruct::default();
expected.insert("a", 3);
@ -64,7 +63,9 @@ mod tests {
expected.insert("e", 7);
assert!(
expected.reflect_partial_eq(&deserialized).unwrap(),
expected
.reflect_partial_eq(deserialized.as_partial_reflect())
.unwrap(),
"Deserialization failed: expected {expected:?} found {deserialized:?}"
);
@ -75,7 +76,8 @@ mod tests {
d: -1,
e: 7,
};
let received = <TestStruct as FromReflect>::from_reflect(&deserialized).unwrap();
let received =
<TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
assert_eq!(
expected, received,
@ -112,8 +114,7 @@ mod tests {
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let deserialized = value.take::<DynamicTupleStruct>().unwrap();
let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let mut expected = DynamicTupleStruct::default();
expected.insert(3);
@ -123,12 +124,15 @@ mod tests {
expected.insert(7);
assert!(
expected.reflect_partial_eq(&deserialized).unwrap(),
expected
.reflect_partial_eq(deserialized.as_partial_reflect())
.unwrap(),
"Deserialization failed: expected {expected:?} found {deserialized:?}"
);
let expected = TestStruct(3, 0, 0, -1, 7);
let received = <TestStruct as FromReflect>::from_reflect(&deserialized).unwrap();
let received =
<TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
assert_eq!(
expected, received,
@ -173,12 +177,10 @@ mod tests {
let reflect_deserializer = ReflectDeserializer::new(&registry);
let expected = value.clone_value();
let result = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap()
.take::<DynamicStruct>()
.unwrap();
let result = reflect_deserializer.deserialize(&mut deserializer).unwrap();
assert!(expected.reflect_partial_eq(&result).unwrap());
assert!(expected
.reflect_partial_eq(result.as_partial_reflect())
.unwrap());
}
}

View file

@ -1,6 +1,6 @@
use crate::{
Array, Enum, List, Map, Reflect, ReflectRef, ReflectSerialize, Set, Struct, Tuple, TupleStruct,
TypeInfo, TypeRegistry, VariantInfo, VariantType,
Array, Enum, List, Map, PartialReflect, ReflectRef, ReflectSerialize, Set, Struct, Tuple,
TupleStruct, TypeInfo, TypeRegistry, VariantInfo, VariantType,
};
use serde::ser::{
Error, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct,
@ -29,9 +29,15 @@ impl<'a> Serializable<'a> {
}
fn get_serializable<'a, E: Error>(
reflect_value: &'a dyn Reflect,
reflect_value: &'a dyn PartialReflect,
type_registry: &TypeRegistry,
) -> Result<Serializable<'a>, E> {
let Some(reflect_value) = reflect_value.try_as_reflect() else {
return Err(Error::custom(format_args!(
"Type '{}' does not implement `Reflect`",
reflect_value.reflect_type_path()
)));
};
let info = reflect_value.get_represented_type_info().ok_or_else(|| {
Error::custom(format_args!(
"Type '{}' does not represent any type",
@ -93,12 +99,12 @@ fn get_serializable<'a, E: Error>(
/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
/// [type path]: crate::TypePath::type_path
pub struct ReflectSerializer<'a> {
pub value: &'a dyn Reflect,
pub value: &'a dyn PartialReflect,
pub registry: &'a TypeRegistry,
}
impl<'a> ReflectSerializer<'a> {
pub fn new(value: &'a dyn Reflect, registry: &'a TypeRegistry) -> Self {
pub fn new(value: &'a dyn PartialReflect, registry: &'a TypeRegistry) -> Self {
ReflectSerializer { value, registry }
}
}
@ -171,12 +177,12 @@ impl<'a> Serialize for ReflectSerializer<'a> {
/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
/// [type path]: crate::TypePath::type_path
pub struct TypedReflectSerializer<'a> {
pub value: &'a dyn Reflect,
pub value: &'a dyn PartialReflect,
pub registry: &'a TypeRegistry,
}
impl<'a> TypedReflectSerializer<'a> {
pub fn new(value: &'a dyn Reflect, registry: &'a TypeRegistry) -> Self {
pub fn new(value: &'a dyn PartialReflect, registry: &'a TypeRegistry) -> Self {
TypedReflectSerializer { value, registry }
}
}
@ -240,7 +246,7 @@ impl<'a> Serialize for TypedReflectSerializer<'a> {
pub struct ReflectValueSerializer<'a> {
pub registry: &'a TypeRegistry,
pub value: &'a dyn Reflect,
pub value: &'a dyn PartialReflect,
}
impl<'a> Serialize for ReflectValueSerializer<'a> {
@ -565,7 +571,7 @@ impl<'a> Serialize for ArraySerializer<'a> {
#[cfg(test)]
mod tests {
use crate::serde::ReflectSerializer;
use crate::{self as bevy_reflect, Struct};
use crate::{self as bevy_reflect, PartialReflect, Struct};
use crate::{Reflect, ReflectSerialize, TypeRegistry};
use bevy_utils::{HashMap, HashSet};
use ron::extensions::Extensions;
@ -946,7 +952,7 @@ mod tests {
none: None,
};
let dynamic = value.clone_dynamic();
let reflect = dynamic.as_reflect();
let reflect = dynamic.as_partial_reflect();
let registry = get_registry();

View file

@ -6,8 +6,8 @@ use bevy_utils::hashbrown::hash_table::OccupiedEntry as HashTableOccupiedEntry;
use bevy_utils::hashbrown::HashTable;
use crate::{
self as bevy_reflect, hash_error, ApplyError, Reflect, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo, TypePath, TypePathTable,
self as bevy_reflect, hash_error, ApplyError, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
};
/// A trait used to power [set-like] operations via [reflection].
@ -17,7 +17,7 @@ use crate::{
///
/// # Hashing
///
/// All values are expected to return a valid hash value from [`Reflect::reflect_hash`].
/// All values are expected to return a valid hash value from [`PartialReflect::reflect_hash`].
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding `#[reflect(Hash)]`
/// to the entire struct or enum.
/// This is true even for manual implementors who do not use the hashed value,
@ -26,7 +26,7 @@ use crate::{
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, Set};
/// use bevy_reflect::{PartialReflect, Set};
/// use bevy_utils::HashSet;
///
///
@ -34,17 +34,17 @@ use crate::{
/// foo.insert_boxed(Box::new(123_u32));
/// assert_eq!(foo.len(), 1);
///
/// let field: &dyn Reflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123_u32));
/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123_u32));
/// ```
///
/// [set-like]: https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html
/// [reflection]: crate
pub trait Set: Reflect {
pub trait Set: PartialReflect {
/// Returns a reference to the value.
///
/// If no value is contained, returns `None`.
fn get(&self, value: &dyn Reflect) -> Option<&dyn Reflect>;
fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
/// Returns the number of elements in the set.
fn len(&self) -> usize;
@ -55,10 +55,10 @@ pub trait Set: Reflect {
}
/// Returns an iterator over the values of the set.
fn iter(&self) -> Box<dyn Iterator<Item = &dyn Reflect> + '_>;
fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_>;
/// Drain the values of this set to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>>;
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the set, producing a [`DynamicSet`].
fn clone_dynamic(&self) -> DynamicSet;
@ -67,16 +67,16 @@ pub trait Set: Reflect {
///
/// If the set did not have this value present, `true` is returned.
/// If the set did have this value present, `false` is returned.
fn insert_boxed(&mut self, value: Box<dyn Reflect>) -> bool;
fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool;
/// Removes a value from the set.
///
/// If the set did not have this value present, `true` is returned.
/// If the set did have this value present, `false` is returned.
fn remove(&mut self, value: &dyn Reflect) -> bool;
fn remove(&mut self, value: &dyn PartialReflect) -> bool;
/// Checks if the given value is contained in the set
fn contains(&self, value: &dyn Reflect) -> bool;
fn contains(&self, value: &dyn PartialReflect) -> bool;
}
/// A container for compile-time set info.
@ -164,7 +164,7 @@ impl SetInfo {
#[derive(Default)]
pub struct DynamicSet {
represented_type: Option<&'static TypeInfo>,
hash_table: HashTable<Box<dyn Reflect>>,
hash_table: HashTable<Box<dyn PartialReflect>>,
}
impl DynamicSet {
@ -192,13 +192,13 @@ impl DynamicSet {
self.insert_boxed(Box::new(value));
}
#[allow(clippy::borrowed_box)]
fn internal_hash(value: &Box<dyn Reflect>) -> u64 {
fn internal_hash(value: &dyn PartialReflect) -> u64 {
value.reflect_hash().expect(hash_error!(value))
}
#[allow(clippy::borrowed_box)]
fn internal_eq(value: &Box<dyn Reflect>) -> impl FnMut(&Box<dyn Reflect>) -> bool + '_ {
fn internal_eq(
value: &dyn PartialReflect,
) -> impl FnMut(&Box<dyn PartialReflect>) -> bool + '_ {
|other| {
value
.reflect_partial_eq(&**other)
@ -207,18 +207,10 @@ impl DynamicSet {
}
}
// I just created this function to have only one point where we ignore the rust warning about the
// unused allocation
fn box_and_clone(val: &dyn Reflect) -> Box<dyn Reflect> {
#[allow(unused_allocation)]
Box::new(val).clone_value()
}
impl Set for DynamicSet {
fn get(&self, value: &dyn Reflect) -> Option<&dyn Reflect> {
let boxed = box_and_clone(value);
fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
self.hash_table
.find(Self::internal_hash(&boxed), Self::internal_eq(&boxed))
.find(Self::internal_hash(value), Self::internal_eq(value))
.map(|value| &**value)
}
@ -226,12 +218,12 @@ impl Set for DynamicSet {
self.hash_table.len()
}
fn iter(&self) -> Box<dyn Iterator<Item = &dyn Reflect> + '_> {
fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_> {
let iter = self.hash_table.iter().map(|v| &**v);
Box::new(iter)
}
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.hash_table.into_iter().collect::<Vec<_>>()
}
@ -241,7 +233,9 @@ impl Set for DynamicSet {
.iter()
.map(|value| value.clone_value())
.for_each(|value| {
hash_table.insert_unique(Self::internal_hash(&value), value, Self::internal_hash);
hash_table.insert_unique(Self::internal_hash(value.as_ref()), value, |boxed| {
Self::internal_hash(boxed.as_ref())
});
});
DynamicSet {
@ -250,7 +244,7 @@ impl Set for DynamicSet {
}
}
fn insert_boxed(&mut self, value: Box<dyn Reflect>) -> bool {
fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool {
assert_eq!(
value.reflect_partial_eq(&*value),
Some(true),
@ -258,7 +252,7 @@ impl Set for DynamicSet {
);
match self
.hash_table
.find_mut(Self::internal_hash(&value), Self::internal_eq(&value))
.find_mut(Self::internal_hash(&*value), Self::internal_eq(&*value))
{
Some(old) => {
*old = value;
@ -266,77 +260,73 @@ impl Set for DynamicSet {
}
None => {
self.hash_table.insert_unique(
Self::internal_hash(&value),
Self::internal_hash(value.as_ref()),
value,
Self::internal_hash,
|boxed| Self::internal_hash(boxed.as_ref()),
);
true
}
}
}
fn remove(&mut self, value: &dyn Reflect) -> bool {
let boxed = box_and_clone(value);
fn remove(&mut self, value: &dyn PartialReflect) -> bool {
self.hash_table
.find_entry(Self::internal_hash(&boxed), Self::internal_eq(&boxed))
.find_entry(Self::internal_hash(value), Self::internal_eq(value))
.map(HashTableOccupiedEntry::remove)
.is_ok()
}
fn contains(&self, value: &dyn Reflect) -> bool {
let boxed = box_and_clone(value);
fn contains(&self, value: &dyn PartialReflect) -> bool {
self.hash_table
.find(Self::internal_hash(&boxed), Self::internal_eq(&boxed))
.find(Self::internal_hash(value), Self::internal_eq(value))
.is_some()
}
}
impl Reflect for DynamicSet {
impl PartialReflect for DynamicSet {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn apply(&mut self, value: &dyn Reflect) {
#[inline]
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn PartialReflect) {
set_apply(self, value);
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
set_try_apply(self, value)
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Set
}
@ -353,11 +343,11 @@ impl Reflect for DynamicSet {
ReflectOwned::Set(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
set_partial_eq(self, value)
}
@ -381,8 +371,8 @@ impl Debug for DynamicSet {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicSet {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(values: I) -> Self {
impl FromIterator<Box<dyn PartialReflect>> for DynamicSet {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
let mut this = Self {
represented_type: None,
hash_table: HashTable::new(),
@ -412,7 +402,7 @@ impl<T: Reflect> FromIterator<T> for DynamicSet {
}
impl IntoIterator for DynamicSet {
type Item = Box<dyn Reflect>;
type Item = Box<dyn PartialReflect>;
type IntoIter = bevy_utils::hashbrown::hash_table::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -421,28 +411,28 @@ impl IntoIterator for DynamicSet {
}
impl<'a> IntoIterator for &'a DynamicSet {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
type IntoIter = std::iter::Map<
bevy_utils::hashbrown::hash_table::Iter<'a, Box<dyn Reflect>>,
fn(&'a Box<dyn Reflect>) -> Self::Item,
bevy_utils::hashbrown::hash_table::Iter<'a, Box<dyn PartialReflect>>,
fn(&'a Box<dyn PartialReflect>) -> Self::Item,
>;
fn into_iter(self) -> Self::IntoIter {
self.hash_table.iter().map(|v| v.as_reflect())
self.hash_table.iter().map(|v| v.as_ref())
}
}
/// Compares a [`Set`] with a [`Reflect`] value.
/// Compares a [`Set`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a set;
/// - `b` is the same length as `a`;
/// - For each value pair in `a`, `b` contains the value too,
/// and [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two values.
/// and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn set_partial_eq<M: Set>(a: &M, b: &dyn Reflect) -> Option<bool> {
pub fn set_partial_eq<M: Set>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Set(set) = b.reflect_ref() else {
return Some(false);
};
@ -499,7 +489,7 @@ pub fn set_debug(dyn_set: &dyn Set, f: &mut Formatter<'_>) -> std::fmt::Result {
///
/// This function panics if `b` is not a reflected set.
#[inline]
pub fn set_apply<M: Set>(a: &mut M, b: &dyn Reflect) {
pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
if let ReflectRef::Set(set_value) = b.reflect_ref() {
for b_value in set_value.iter() {
if a.get(b_value).is_none() {
@ -521,7 +511,7 @@ pub fn set_apply<M: Set>(a: &mut M, b: &dyn Reflect) {
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected set or if
/// applying elements to each other fails.
#[inline]
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn Reflect) -> Result<(), ApplyError> {
pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::Set(set_value) = b.reflect_ref() {
for b_value in set_value.iter() {
if a.get(b_value).is_none() {
@ -551,7 +541,9 @@ mod tests {
set.insert(expected[2].to_string());
for item in set.into_iter() {
let value = item.take::<String>().expect("couldn't downcast to String");
let value = item
.try_take::<String>()
.expect("couldn't downcast to String");
let index = expected
.iter()
.position(|i| *i == value.as_str())

View file

@ -1,7 +1,7 @@
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::{
self as bevy_reflect, ApplyError, NamedField, Reflect, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, TypeInfo, TypePath, TypePathTable,
self as bevy_reflect, ApplyError, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
};
use bevy_reflect_derive::impl_type_path;
use bevy_utils::HashMap;
@ -25,7 +25,7 @@ use std::{
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, Struct};
/// use bevy_reflect::{PartialReflect, Reflect, Struct};
///
/// #[derive(Reflect)]
/// struct Foo {
@ -37,30 +37,30 @@ use std::{
/// assert_eq!(foo.field_len(), 1);
/// assert_eq!(foo.name_at(0), Some("bar"));
///
/// let field: &dyn Reflect = foo.field("bar").unwrap();
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
/// let field: &dyn PartialReflect = foo.field("bar").unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html
/// [reflection]: crate
/// [unit structs]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
pub trait Struct: Reflect {
pub trait Struct: PartialReflect {
/// Returns a reference to the value of the field named `name` as a `&dyn
/// Reflect`.
fn field(&self, name: &str) -> Option<&dyn Reflect>;
/// PartialReflect`.
fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field named `name` as a
/// `&mut dyn Reflect`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;
/// `&mut dyn PartialReflect`.
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
fn field_at(&self, index: usize) -> Option<&dyn Reflect>;
/// `&dyn PartialReflect`.
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn Reflect`.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
/// as a `&mut dyn PartialReflect`.
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the name of the field with index `index`.
fn name_at(&self, index: usize) -> Option<&str>;
@ -214,7 +214,7 @@ impl<'a> FieldIter<'a> {
}
impl<'a> Iterator for FieldIter<'a> {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.struct_val.field_at(self.index);
@ -262,23 +262,25 @@ pub trait GetField {
impl<S: Struct> GetField for S {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name).and_then(|value| value.downcast_ref::<T>())
self.field(name)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.downcast_mut::<T>())
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetField for dyn Struct {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name).and_then(|value| value.downcast_ref::<T>())
self.field(name)
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.downcast_mut::<T>())
.and_then(|value| value.try_downcast_mut::<T>())
}
}
@ -286,7 +288,7 @@ impl GetField for dyn Struct {
#[derive(Default)]
pub struct DynamicStruct {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn Reflect>>,
fields: Vec<Box<dyn PartialReflect>>,
field_names: Vec<Cow<'static, str>>,
field_indices: HashMap<Cow<'static, str>, usize>,
}
@ -314,7 +316,11 @@ impl DynamicStruct {
/// Inserts a field named `name` with value `value` into the struct.
///
/// If the field already exists, it is overwritten.
pub fn insert_boxed<'a>(&mut self, name: impl Into<Cow<'a, str>>, value: Box<dyn Reflect>) {
pub fn insert_boxed<'a>(
&mut self,
name: impl Into<Cow<'a, str>>,
value: Box<dyn PartialReflect>,
) {
let name: Cow<str> = name.into();
if let Some(index) = self.field_indices.get(&name) {
self.fields[*index] = value;
@ -329,7 +335,7 @@ impl DynamicStruct {
/// Inserts a field named `name` with the typed value `value` into the struct.
///
/// If the field already exists, it is overwritten.
pub fn insert<'a, T: Reflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
self.insert_boxed(name, Box::new(value));
}
@ -341,14 +347,14 @@ impl DynamicStruct {
impl Struct for DynamicStruct {
#[inline]
fn field(&self, name: &str) -> Option<&dyn Reflect> {
fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
self.field_indices
.get(name)
.map(|index| &*self.fields[*index])
}
#[inline]
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
if let Some(index) = self.field_indices.get(name) {
Some(&mut *self.fields[*index])
} else {
@ -357,12 +363,12 @@ impl Struct for DynamicStruct {
}
#[inline]
fn field_at(&self, index: usize) -> Option<&dyn Reflect> {
fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|value| &**value)
}
#[inline]
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|value| &mut **value)
}
@ -398,43 +404,38 @@ impl Struct for DynamicStruct {
}
}
impl Reflect for DynamicStruct {
impl PartialReflect for DynamicStruct {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> {
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_any(&self) -> &dyn Any {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::Struct(struct_value) = value.reflect_ref() {
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
@ -451,12 +452,6 @@ impl Reflect for DynamicStruct {
Ok(())
}
#[inline]
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Struct
@ -478,11 +473,11 @@ impl Reflect for DynamicStruct {
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
struct_partial_eq(self, value)
}
@ -499,8 +494,6 @@ impl Reflect for DynamicStruct {
}
impl_type_path!((in bevy_reflect) DynamicStruct);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicStruct);
impl Debug for DynamicStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@ -508,13 +501,13 @@ impl Debug for DynamicStruct {
}
}
impl<'a, N> FromIterator<(N, Box<dyn Reflect>)> for DynamicStruct
impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
where
N: Into<Cow<'a, str>>,
{
/// Create a dynamic struct that doesn't represent a type from the
/// field name, field value pairs.
fn from_iter<I: IntoIterator<Item = (N, Box<dyn Reflect>)>>(fields: I) -> Self {
fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
let mut dynamic_struct = Self::default();
for (name, value) in fields.into_iter() {
dynamic_struct.insert_boxed(name, value);
@ -524,7 +517,7 @@ where
}
impl IntoIterator for DynamicStruct {
type Item = Box<dyn Reflect>;
type Item = Box<dyn PartialReflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -533,7 +526,7 @@ impl IntoIterator for DynamicStruct {
}
impl<'a> IntoIterator for &'a DynamicStruct {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
type IntoIter = FieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
@ -541,17 +534,17 @@ impl<'a> IntoIterator for &'a DynamicStruct {
}
}
/// Compares a [`Struct`] with a [`Reflect`] value.
/// Compares a [`Struct`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a struct;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
pub fn struct_partial_eq<S: Struct + ?Sized>(a: &S, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
return Some(false);
};

View file

@ -6,7 +6,7 @@ use crate::{
GetTypeRegistration, MaybeTyped, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo,
TypePath, TypeRegistration, TypeRegistry, Typed, UnnamedField,
};
use crate::{ReflectKind, TypePathTable};
use crate::{PartialReflect, ReflectKind, TypePathTable};
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter};
use std::slice::Iter;
@ -22,25 +22,25 @@ use std::slice::Iter;
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, Tuple};
/// use bevy_reflect::{PartialReflect, Tuple};
///
/// let foo = (123_u32, true);
/// assert_eq!(foo.field_len(), 2);
///
/// let field: &dyn Reflect = foo.field(0).unwrap();
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
/// let field: &dyn PartialReflect = foo.field(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [tuple-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
/// [reflection]: crate
pub trait Tuple: Reflect {
pub trait Tuple: PartialReflect {
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
fn field(&self, index: usize) -> Option<&dyn Reflect>;
fn field(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn Reflect`.
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of fields in the tuple.
fn field_len(&self) -> usize;
@ -49,7 +49,7 @@ pub trait Tuple: Reflect {
fn iter_fields(&self) -> TupleFieldIter;
/// Drain the fields of this tuple to get a vector of owned values.
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>>;
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
/// Clones the struct into a [`DynamicTuple`].
fn clone_dynamic(&self) -> DynamicTuple;
@ -71,7 +71,7 @@ impl<'a> TupleFieldIter<'a> {
}
impl<'a> Iterator for TupleFieldIter<'a> {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple.field(self.index);
@ -115,24 +115,24 @@ pub trait GetTupleField {
impl<S: Tuple> GetTupleField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetTupleField for dyn Tuple {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
.and_then(|value| value.try_downcast_mut::<T>())
}
}
@ -222,7 +222,7 @@ impl TupleInfo {
#[derive(Default, Debug)]
pub struct DynamicTuple {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn Reflect>>,
fields: Vec<Box<dyn PartialReflect>>,
}
impl DynamicTuple {
@ -245,13 +245,13 @@ impl DynamicTuple {
}
/// Appends an element with value `value` to the tuple.
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
pub fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) {
self.represented_type = None;
self.fields.push(value);
}
/// Appends a typed element with value `value` to the tuple.
pub fn insert<T: Reflect>(&mut self, value: T) {
pub fn insert<T: PartialReflect>(&mut self, value: T) {
self.represented_type = None;
self.insert_boxed(Box::new(value));
}
@ -259,12 +259,12 @@ impl DynamicTuple {
impl Tuple for DynamicTuple {
#[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> {
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
@ -282,7 +282,7 @@ impl Tuple for DynamicTuple {
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
self.fields
}
@ -299,51 +299,41 @@ impl Tuple for DynamicTuple {
}
}
impl Reflect for DynamicTuple {
impl PartialReflect for DynamicTuple {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> {
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_any(&self) -> &dyn Any {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn apply(&mut self, value: &dyn Reflect) {
fn apply(&mut self, value: &dyn PartialReflect) {
tuple_apply(self, value);
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
@ -365,15 +355,15 @@ impl Reflect for DynamicTuple {
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
tuple_try_apply(self, value)
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
tuple_partial_eq(self, value)
}
@ -391,8 +381,8 @@ impl Reflect for DynamicTuple {
impl_type_path!((in bevy_reflect) DynamicTuple);
impl FromIterator<Box<dyn Reflect>> for DynamicTuple {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(fields: I) -> Self {
impl FromIterator<Box<dyn PartialReflect>> for DynamicTuple {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
@ -401,7 +391,7 @@ impl FromIterator<Box<dyn Reflect>> for DynamicTuple {
}
impl IntoIterator for DynamicTuple {
type Item = Box<dyn Reflect>;
type Item = Box<dyn PartialReflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -410,7 +400,7 @@ impl IntoIterator for DynamicTuple {
}
impl<'a> IntoIterator for &'a DynamicTuple {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
type IntoIter = TupleFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
@ -424,7 +414,7 @@ impl<'a> IntoIterator for &'a DynamicTuple {
///
/// This function panics if `b` is not a tuple.
#[inline]
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) {
if let Err(err) = tuple_try_apply(a, b) {
panic!("{err}");
}
@ -438,7 +428,7 @@ pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a tuple or if
/// applying elements to each other fails.
#[inline]
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) -> Result<(), ApplyError> {
pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
for (i, value) in tuple.iter_fields().enumerate() {
if let Some(v) = a.field_mut(i) {
@ -454,16 +444,16 @@ pub fn tuple_try_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) -> Result<(), Apply
Ok(())
}
/// Compares a [`Tuple`] with a [`Reflect`] value.
/// Compares a [`Tuple`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple;
/// - `b` has the same number of elements as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
pub fn tuple_partial_eq<T: Tuple + ?Sized>(a: &T, b: &dyn PartialReflect) -> Option<bool> {
let ReflectRef::Tuple(b) = b.reflect_ref() else {
return Some(false);
};
@ -512,17 +502,17 @@ macro_rules! impl_reflect_tuple {
{$($index:tt : $name:tt),*} => {
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Tuple for ($($name,)*) {
#[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> {
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
match index {
$($index => Some(&self.$index as &dyn Reflect),)*
$($index => Some(&self.$index as &dyn PartialReflect),)*
_ => None,
}
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
match index {
$($index => Some(&mut self.$index as &mut dyn Reflect),)*
$($index => Some(&mut self.$index as &mut dyn PartialReflect),)*
_ => None,
}
}
@ -542,7 +532,7 @@ macro_rules! impl_reflect_tuple {
}
#[inline]
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
vec![
$(Box::new(self.$index),)*
]
@ -561,11 +551,70 @@ macro_rules! impl_reflect_tuple {
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Reflect for ($($name,)*) {
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> PartialReflect for ($($name,)*) {
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
Some(<Self as Typed>::type_info())
}
#[inline]
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Ok(self)
}
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
Some(self)
}
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
Some(self)
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Tuple(self)
}
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
crate::tuple_partial_eq(self, value)
}
fn apply(&mut self, value: &dyn PartialReflect) {
crate::tuple_apply(self, value);
}
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
crate::tuple_try_apply(self, value)
}
}
impl<$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Reflect for ($($name,)*) {
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
@ -590,42 +639,10 @@ macro_rules! impl_reflect_tuple {
self
}
fn apply(&mut self, value: &dyn Reflect) {
crate::tuple_apply(self, value);
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
crate::tuple_try_apply(self, value)
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::Tuple
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
ReflectOwned::Tuple(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
crate::tuple_partial_eq(self, value)
}
}
impl <$($name: Reflect + MaybeTyped + TypePath + GetTypeRegistration),*> Typed for ($($name,)*) {
@ -653,7 +670,7 @@ macro_rules! impl_reflect_tuple {
impl<$($name: FromReflect + MaybeTyped + TypePath + GetTypeRegistration),*> FromReflect for ($($name,)*)
{
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() {
Some(
(

View file

@ -2,8 +2,8 @@ use bevy_reflect_derive::impl_type_path;
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
use crate::{
self as bevy_reflect, ApplyError, DynamicTuple, Reflect, ReflectKind, ReflectMut, ReflectOwned,
ReflectRef, Tuple, TypeInfo, TypePath, TypePathTable, UnnamedField,
self as bevy_reflect, ApplyError, DynamicTuple, PartialReflect, Reflect, ReflectKind,
ReflectMut, ReflectOwned, ReflectRef, Tuple, TypeInfo, TypePath, TypePathTable, UnnamedField,
};
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter};
@ -21,7 +21,7 @@ use std::sync::Arc;
/// # Example
///
/// ```
/// use bevy_reflect::{Reflect, TupleStruct};
/// use bevy_reflect::{PartialReflect, Reflect, TupleStruct};
///
/// #[derive(Reflect)]
/// struct Foo(u32);
@ -30,20 +30,20 @@ use std::sync::Arc;
///
/// assert_eq!(foo.field_len(), 1);
///
/// let field: &dyn Reflect = foo.field(0).unwrap();
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
/// let field: &dyn PartialReflect = foo.field(0).unwrap();
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
/// ```
///
/// [tuple struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types
/// [reflection]: crate
pub trait TupleStruct: Reflect {
pub trait TupleStruct: PartialReflect {
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
fn field(&self, index: usize) -> Option<&dyn Reflect>;
fn field(&self, index: usize) -> Option<&dyn PartialReflect>;
/// Returns a mutable reference to the value of the field with index `index`
/// as a `&mut dyn Reflect`.
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
/// Returns the number of fields in the tuple struct.
fn field_len(&self) -> usize;
@ -165,7 +165,7 @@ impl<'a> TupleStructFieldIter<'a> {
}
impl<'a> Iterator for TupleStructFieldIter<'a> {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple_struct.field(self.index);
@ -212,24 +212,24 @@ pub trait GetTupleStructField {
impl<S: TupleStruct> GetTupleStructField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
.and_then(|value| value.try_downcast_mut::<T>())
}
}
impl GetTupleStructField for dyn TupleStruct {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
.and_then(|value| value.try_downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
.and_then(|value| value.try_downcast_mut::<T>())
}
}
@ -237,7 +237,7 @@ impl GetTupleStructField for dyn TupleStruct {
#[derive(Default)]
pub struct DynamicTupleStruct {
represented_type: Option<&'static TypeInfo>,
fields: Vec<Box<dyn Reflect>>,
fields: Vec<Box<dyn PartialReflect>>,
}
impl DynamicTupleStruct {
@ -261,24 +261,24 @@ impl DynamicTupleStruct {
}
/// Appends an element with value `value` to the tuple struct.
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
pub fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) {
self.fields.push(value);
}
/// Appends a typed element with value `value` to the tuple struct.
pub fn insert<T: Reflect>(&mut self, value: T) {
pub fn insert<T: PartialReflect>(&mut self, value: T) {
self.insert_boxed(Box::new(value));
}
}
impl TupleStruct for DynamicTupleStruct {
#[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> {
fn field(&self, index: usize) -> Option<&dyn PartialReflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
@ -307,43 +307,40 @@ impl TupleStruct for DynamicTupleStruct {
}
}
impl Reflect for DynamicTupleStruct {
impl PartialReflect for DynamicTupleStruct {
#[inline]
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
self.represented_type
}
#[inline]
fn into_any(self: Box<Self>) -> Box<dyn Any> {
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
self
}
#[inline]
fn as_any(&self) -> &dyn Any {
fn as_partial_reflect(&self) -> &dyn PartialReflect {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
self
}
#[inline]
fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
self
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
Err(self)
}
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
None
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
None
}
fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
if let ReflectRef::TupleStruct(tuple_struct) = value.reflect_ref() {
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(v) = self.field_mut(i) {
@ -359,12 +356,6 @@ impl Reflect for DynamicTupleStruct {
Ok(())
}
#[inline]
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_kind(&self) -> ReflectKind {
ReflectKind::TupleStruct
@ -386,12 +377,12 @@ impl Reflect for DynamicTupleStruct {
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
fn clone_value(&self) -> Box<dyn PartialReflect> {
Box::new(self.clone_dynamic())
}
#[inline]
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
tuple_struct_partial_eq(self, value)
}
@ -408,8 +399,6 @@ impl Reflect for DynamicTupleStruct {
}
impl_type_path!((in bevy_reflect) DynamicTupleStruct);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicTupleStruct);
impl Debug for DynamicTupleStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@ -426,8 +415,8 @@ impl From<DynamicTuple> for DynamicTupleStruct {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicTupleStruct {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(fields: I) -> Self {
impl FromIterator<Box<dyn PartialReflect>> for DynamicTupleStruct {
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
@ -436,7 +425,7 @@ impl FromIterator<Box<dyn Reflect>> for DynamicTupleStruct {
}
impl IntoIterator for DynamicTupleStruct {
type Item = Box<dyn Reflect>;
type Item = Box<dyn PartialReflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
@ -445,7 +434,7 @@ impl IntoIterator for DynamicTupleStruct {
}
impl<'a> IntoIterator for &'a DynamicTupleStruct {
type Item = &'a dyn Reflect;
type Item = &'a dyn PartialReflect;
type IntoIter = TupleStructFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
@ -453,16 +442,19 @@ impl<'a> IntoIterator for &'a DynamicTupleStruct {
}
}
/// Compares a [`TupleStruct`] with a [`Reflect`] value.
/// Compares a [`TupleStruct`] with a [`PartialReflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple struct;
/// - `b` has the same number of fields as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.
/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_struct_partial_eq<S: TupleStruct>(a: &S, b: &dyn Reflect) -> Option<bool> {
pub fn tuple_struct_partial_eq<S: TupleStruct + ?Sized>(
a: &S,
b: &dyn PartialReflect,
) -> Option<bool> {
let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() else {
return Some(false);
};

View file

@ -1,7 +1,7 @@
use crate::{
ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicStruct, DynamicTuple,
DynamicTupleStruct, EnumInfo, ListInfo, MapInfo, Reflect, ReflectKind, SetInfo, StructInfo,
TupleInfo, TupleStructInfo, TypePath, TypePathTable,
DynamicTupleStruct, EnumInfo, ListInfo, MapInfo, PartialReflect, Reflect, ReflectKind, SetInfo,
StructInfo, TupleInfo, TupleStructInfo, TypePath, TypePathTable,
};
use std::any::{Any, TypeId};
use std::fmt::Debug;
@ -27,7 +27,7 @@ use thiserror::Error;
///
/// ```
/// # use std::any::Any;
/// # use bevy_reflect::{DynamicTypePath, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, TypePath, ValueInfo, ApplyError};
/// # use bevy_reflect::{DynamicTypePath, NamedField, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, TypeInfo, TypePath, ValueInfo, ApplyError};
/// # use bevy_reflect::utility::NonGenericTypeInfoCell;
/// use bevy_reflect::Typed;
///
@ -54,20 +54,28 @@ use thiserror::Error;
/// # fn type_path() -> &'static str { todo!() }
/// # fn short_type_path() -> &'static str { todo!() }
/// # }
/// # impl PartialReflect for MyStruct {
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> { todo!() }
/// # fn as_partial_reflect(&self) -> &dyn PartialReflect { todo!() }
/// # fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { todo!() }
/// # fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> { todo!() }
/// # fn try_as_reflect(&self) -> Option<&dyn Reflect> { todo!() }
/// # fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { todo!() }
/// # fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { 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 PartialReflect> { todo!() }
/// # }
/// # impl Reflect for MyStruct {
/// # 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 try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> { 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 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 set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> { todo!() }
/// # }
/// ```
///
@ -93,7 +101,7 @@ pub trait Typed: Reflect + TypePath {
/// This trait has a blanket implementation for all types that implement `Typed`
/// and manual implementations for all dynamic types (which simply return `None`).
#[doc(hidden)]
pub trait MaybeTyped: Reflect {
pub trait MaybeTyped: PartialReflect {
/// Returns the compile-time [info] for the underlying type, if it exists.
///
/// [info]: TypeInfo
@ -140,12 +148,12 @@ pub enum TypeInfoError {
/// Generally, for any given type, this value can be retrieved one of three ways:
///
/// 1. [`Typed::type_info`]
/// 2. [`Reflect::get_represented_type_info`]
/// 2. [`PartialReflect::get_represented_type_info`]
/// 3. [`TypeRegistry::get_type_info`]
///
/// Each return a static reference to [`TypeInfo`], but they all have their own use cases.
/// For example, if you know the type at compile time, [`Typed::type_info`] is probably
/// the simplest. If all you have is a `dyn Reflect`, you'll probably want [`Reflect::get_represented_type_info`].
/// the simplest. If all you have is a `dyn PartialReflect`, you'll probably want [`PartialReflect::get_represented_type_info`].
/// Lastly, if all you have is a [`TypeId`] or [type path], you will need to go through
/// [`TypeRegistry::get_type_info`].
///
@ -153,8 +161,8 @@ pub enum TypeInfoError {
/// it can be more performant. This is because those other methods may require attaining a lock on
/// the static [`TypeInfo`], while the registry simply checks a map.
///
/// [`Reflect::get_represented_type_info`]: Reflect::get_represented_type_info
/// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info
/// [`PartialReflect::get_represented_type_info`]: crate::PartialReflect::get_represented_type_info
/// [type path]: TypePath::type_path
#[derive(Debug, Clone)]
pub enum TypeInfo {

View file

@ -584,7 +584,7 @@ impl<T: TypePath + FromReflect + erased_serde::Serialize> FromType<T> for Reflec
value
.downcast_ref::<T>()
.map(|value| Serializable::Borrowed(value))
.or_else(|| T::from_reflect(value).map(|value| Serializable::Owned(Box::new(value))))
.or_else(|| T::from_reflect(value.as_partial_reflect()).map(|value| Serializable::Owned(Box::new(value))))
.unwrap_or_else(|| {
panic!(
"FromReflect::from_reflect failed when called on type `{}` with this value: {value:?}",
@ -788,7 +788,11 @@ mod test {
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect(Ptr::from(&value)) };
match dyn_reflect.reflect_ref() {
bevy_reflect::ReflectRef::Struct(strukt) => {
let a = strukt.field("a").unwrap().downcast_ref::<f32>().unwrap();
let a = strukt
.field("a")
.unwrap()
.try_downcast_ref::<f32>()
.unwrap();
assert_eq!(*a, 2.0);
}
_ => panic!("invalid reflection"),

View file

@ -49,7 +49,7 @@ mod sealed {
///
/// ```
/// # use std::any::Any;
/// # use bevy_reflect::{DynamicTypePath, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, Typed, TypeInfo, TypePath, ApplyError};
/// # use bevy_reflect::{DynamicTypePath, NamedField, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, StructInfo, Typed, TypeInfo, TypePath, ApplyError};
/// use bevy_reflect::utility::NonGenericTypeInfoCell;
///
/// struct Foo {
@ -70,20 +70,28 @@ mod sealed {
/// # fn type_path() -> &'static str { todo!() }
/// # fn short_type_path() -> &'static str { todo!() }
/// # }
/// # impl Reflect for Foo {
/// # impl PartialReflect for Foo {
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> { todo!() }
/// # fn as_partial_reflect(&self) -> &dyn PartialReflect { todo!() }
/// # fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { todo!() }
/// # fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> { todo!() }
/// # fn try_as_reflect(&self) -> Option<&dyn Reflect> { todo!() }
/// # fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { todo!() }
/// # fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { 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 PartialReflect> { todo!() }
/// # }
/// # impl Reflect for Foo {
/// # 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 try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> { 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!() }
/// # }
/// ```
///
@ -130,7 +138,7 @@ impl<T: TypedProperty> Default for NonGenericTypeCell<T> {
///
/// ```
/// # use std::any::Any;
/// # use bevy_reflect::{DynamicTypePath, Reflect, ReflectMut, ReflectOwned, ReflectRef, TupleStructInfo, Typed, TypeInfo, TypePath, UnnamedField, ApplyError};
/// # use bevy_reflect::{DynamicTypePath, PartialReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TupleStructInfo, Typed, TypeInfo, TypePath, UnnamedField, ApplyError};
/// use bevy_reflect::utility::GenericTypeInfoCell;
///
/// struct Foo<T>(T);
@ -149,20 +157,28 @@ impl<T: TypedProperty> Default for NonGenericTypeCell<T> {
/// # fn type_path() -> &'static str { todo!() }
/// # fn short_type_path() -> &'static str { todo!() }
/// # }
/// # impl<T: Reflect + Typed + TypePath> Reflect for Foo<T> {
/// # impl<T: PartialReflect + TypePath> PartialReflect for Foo<T> {
/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() }
/// # fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> { todo!() }
/// # fn as_partial_reflect(&self) -> &dyn PartialReflect { todo!() }
/// # fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect { todo!() }
/// # fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> { todo!() }
/// # fn try_as_reflect(&self) -> Option<&dyn Reflect> { todo!() }
/// # fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> { todo!() }
/// # fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> { 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 PartialReflect> { todo!() }
/// # }
/// # impl<T: Reflect + TypePath> Reflect for Foo<T> {
/// # 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 try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> { 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!() }
/// # }
/// ```
///

View file

@ -5,7 +5,7 @@ use bevy_ecs::{
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
world::World,
};
use bevy_reflect::{Reflect, TypePath, TypeRegistry};
use bevy_reflect::{PartialReflect, TypePath, TypeRegistry};
use bevy_utils::TypeIdMap;
#[cfg(feature = "serialize")]
@ -28,7 +28,7 @@ use serde::Serialize;
#[derive(Asset, TypePath, Default)]
pub struct DynamicScene {
/// Resources stored in the dynamic scene.
pub resources: Vec<Box<dyn Reflect>>,
pub resources: Vec<Box<dyn PartialReflect>>,
/// Entities contained in the dynamic scene.
pub entities: Vec<DynamicEntity>,
}
@ -40,8 +40,8 @@ pub struct DynamicEntity {
/// Components that reference this entity must consistently use this identifier.
pub entity: Entity,
/// A vector of boxed components that belong to the given entity and
/// implement the [`Reflect`] trait.
pub components: Vec<Box<dyn Reflect>>,
/// implement the [`PartialReflect`] trait.
pub components: Vec<Box<dyn PartialReflect>>,
}
impl DynamicScene {
@ -117,7 +117,11 @@ impl DynamicScene {
// If the entity already has the given component attached,
// just apply the (possibly) new value, otherwise add the
// component to the entity.
reflect_component.apply_or_insert(entity_mut, &**component, &type_registry);
reflect_component.apply_or_insert(
entity_mut,
component.as_partial_reflect(),
&type_registry,
);
}
}

View file

@ -6,7 +6,7 @@ use bevy_ecs::{
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
world::World,
};
use bevy_reflect::Reflect;
use bevy_reflect::PartialReflect;
use bevy_utils::default;
use std::collections::BTreeMap;
@ -52,8 +52,10 @@ use std::collections::BTreeMap;
/// # let entity = world.spawn(ComponentA).id();
/// let dynamic_scene = DynamicSceneBuilder::from_world(&world).extract_entity(entity).build();
/// ```
///
/// [`Reflect`]: bevy_reflect::Reflect
pub struct DynamicSceneBuilder<'w> {
extracted_resources: BTreeMap<ComponentId, Box<dyn Reflect>>,
extracted_resources: BTreeMap<ComponentId, Box<dyn PartialReflect>>,
extracted_scene: BTreeMap<Entity, DynamicEntity>,
component_filter: SceneFilter,
resource_filter: SceneFilter,

View file

@ -3,9 +3,10 @@
use crate::{DynamicEntity, DynamicScene};
use bevy_ecs::entity::Entity;
use bevy_reflect::serde::{TypedReflectDeserializer, TypedReflectSerializer};
use bevy_reflect::PartialReflect;
use bevy_reflect::{
serde::{ReflectDeserializer, TypeRegistrationDeserializer},
Reflect, TypeRegistry,
TypeRegistry,
};
use bevy_utils::HashSet;
use serde::ser::SerializeMap;
@ -155,7 +156,7 @@ impl<'a> Serialize for EntitySerializer<'a> {
/// deserializing through [`SceneMapDeserializer`].
pub struct SceneMapSerializer<'a> {
/// List of boxed values of unique type to serialize.
pub entries: &'a [Box<dyn Reflect>],
pub entries: &'a [Box<dyn PartialReflect>],
/// Type registry in which the types used in `entries` are registered.
pub registry: &'a TypeRegistry,
}
@ -169,7 +170,7 @@ impl<'a> Serialize for SceneMapSerializer<'a> {
for reflect in self.entries {
state.serialize_entry(
reflect.get_represented_type_info().unwrap().type_path(),
&TypedReflectSerializer::new(&**reflect, self.registry),
&TypedReflectSerializer::new(reflect.as_partial_reflect(), self.registry),
)?;
}
state.end()
@ -419,7 +420,7 @@ pub struct SceneMapDeserializer<'a> {
}
impl<'a, 'de> DeserializeSeed<'de> for SceneMapDeserializer<'a> {
type Value = Vec<Box<dyn Reflect>>;
type Value = Vec<Box<dyn PartialReflect>>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
@ -436,7 +437,7 @@ struct SceneMapVisitor<'a> {
}
impl<'a, 'de> Visitor<'de> for SceneMapVisitor<'a> {
type Value = Vec<Box<dyn Reflect>>;
type Value = Vec<Box<dyn PartialReflect>>;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("map of reflect types")

View file

@ -2,7 +2,7 @@ use crate::state::{FreelyMutableState, NextState, State, States};
use bevy_ecs::reflect::from_reflect_with_fallback;
use bevy_ecs::world::World;
use bevy_reflect::{FromType, Reflect, TypeRegistry};
use bevy_reflect::{FromType, Reflect, TypePath, TypeRegistry};
/// A struct used to operate on the reflected [`States`] trait of a type.
///
@ -68,7 +68,7 @@ impl ReflectFreelyMutableStateFns {
///
/// This is useful if you want to start with the default implementation before overriding some
/// of the functions to create a custom implementation.
pub fn new<T: FreelyMutableState + Reflect>() -> Self {
pub fn new<T: FreelyMutableState + Reflect + TypePath>() -> Self {
<ReflectFreelyMutableState as FromType<T>>::from_type().0
}
}
@ -80,11 +80,15 @@ impl ReflectFreelyMutableState {
}
}
impl<S: FreelyMutableState + Reflect> FromType<S> for ReflectFreelyMutableState {
impl<S: FreelyMutableState + Reflect + TypePath> FromType<S> for ReflectFreelyMutableState {
fn from_type() -> Self {
ReflectFreelyMutableState(ReflectFreelyMutableStateFns {
set_next_state: |world, reflected_state, registry| {
let new_state: S = from_reflect_with_fallback(reflected_state, world, registry);
let new_state: S = from_reflect_with_fallback(
reflected_state.as_partial_reflect(),
world,
registry,
);
if let Some(mut next_state) = world.get_resource_mut::<NextState<S>>() {
next_state.set(new_state);
}

View file

@ -3,8 +3,8 @@
use bevy::reflect::{
reflect_trait, serde::TypedReflectDeserializer, std_traits::ReflectDefault, DynamicArray,
DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
DynamicTupleStruct, DynamicVariant, FromReflect, Reflect, ReflectFromReflect, ReflectRef, Set,
TypeRegistry, Typed,
DynamicTupleStruct, DynamicVariant, FromReflect, PartialReflect, Reflect, ReflectFromReflect,
ReflectRef, Set, TypeRegistry, Typed,
};
use serde::de::DeserializeSeed;
use std::collections::{HashMap, HashSet};
@ -34,6 +34,7 @@ fn main() {
// When working with reflected types, however, we often "erase" this type information
// using the `Reflect` trait object.
// This trait object also gives us access to all the methods in the `PartialReflect` trait too.
// The underlying type is still the same (in this case, `Player`),
// but now we've hidden that information from the compiler.
let reflected: Box<dyn Reflect> = Box::new(player);
@ -41,23 +42,24 @@ fn main() {
// Because it's the same type under the hood, we can still downcast it back to the original type.
assert!(reflected.downcast_ref::<Player>().is_some());
// But now let's "clone" our type using `Reflect::clone_value`.
let cloned: Box<dyn Reflect> = reflected.clone_value();
// But now let's "clone" our type using `PartialReflect::clone_value`.
// Notice here we bind it as a `dyn PartialReflect`.
let cloned: Box<dyn PartialReflect> = reflected.clone_value();
// If we try to downcast back to `Player`, we'll get an error.
assert!(cloned.downcast_ref::<Player>().is_none());
// If we try and convert it to a `dyn Reflect` trait object, we'll get an error.
assert!(cloned.try_as_reflect().is_none());
// Why is this?
// Well the reason is that `Reflect::clone_value` actually creates a dynamic type.
// Since `Player` is a struct, we actually get a `DynamicStruct` back.
assert!(cloned.is::<DynamicStruct>());
// Well the reason is that `PartialReflect::clone_value` actually creates a dynamic type.
// Since `Player` is a struct, our trait object is actually a value of `DynamicStruct`.
assert!(cloned.is_dynamic());
// This dynamic type is used to represent (or "proxy") the original type,
// so that we can continue to access its fields and overall structure.
let ReflectRef::Struct(cloned_ref) = cloned.reflect_ref() else {
panic!("expected struct")
};
let id = cloned_ref.field("id").unwrap().downcast_ref::<u32>();
let id = cloned_ref.field("id").unwrap().try_downcast_ref::<u32>();
assert_eq!(id, Some(&123));
// It also enables us to create a representation of a type without having compile-time
@ -73,7 +75,6 @@ fn main() {
.unwrap();
// Our deserialized output is a `DynamicStruct` that proxies/represents a `Player`.
assert!(deserialized.downcast_ref::<DynamicStruct>().is_some());
assert!(deserialized.represents::<Player>());
// And while this does allow us to access the fields and structure of the type,
@ -84,20 +85,24 @@ fn main() {
.data::<ReflectIdentifiable>()
.expect("`ReflectIdentifiable` should be registered");
// Trying to access the registry with our `deserialized` will give a compile error
// since it doesn't implement `Reflect`, only `PartialReflect`.
// Similarly, trying to force the operation will fail.
// This fails since the underlying type of `deserialized` is `DynamicStruct` and not `Player`.
assert!(reflect_identifiable
.get(deserialized.as_reflect())
assert!(deserialized
.try_as_reflect()
.and_then(|reflect_trait_obj| reflect_identifiable.get(reflect_trait_obj))
.is_none());
// So how can we go from a dynamic type to a concrete type?
// There are two ways:
// 1. Using `Reflect::apply`.
// 1. Using `PartialReflect::apply`.
{
// If you know the type at compile time, you can construct a new value and apply the dynamic
// value to it.
let mut value = Player::default();
value.apply(deserialized.as_reflect());
value.apply(deserialized.as_ref());
assert_eq!(value.id, 123);
// If you don't know the type at compile time, you need a dynamic way of constructing
@ -107,7 +112,7 @@ fn main() {
.expect("`ReflectDefault` should be registered");
let mut value: Box<dyn Reflect> = reflect_default.default();
value.apply(deserialized.as_reflect());
value.apply(deserialized.as_ref());
let identifiable: &dyn Identifiable = reflect_identifiable.get(value.as_reflect()).unwrap();
assert_eq!(identifiable.id(), 123);
@ -117,7 +122,7 @@ fn main() {
{
// If you know the type at compile time, you can use the `FromReflect` trait to convert the
// dynamic value into the concrete type directly.
let value: Player = Player::from_reflect(deserialized.as_reflect()).unwrap();
let value: Player = Player::from_reflect(deserialized.as_ref()).unwrap();
assert_eq!(value.id, 123);
// If you don't know the type at compile time, you can use the `ReflectFromReflect` type data
@ -127,14 +132,14 @@ fn main() {
.expect("`ReflectFromReflect` should be registered");
let value: Box<dyn Reflect> = reflect_from_reflect
.from_reflect(deserialized.as_reflect())
.from_reflect(deserialized.as_ref())
.unwrap();
let identifiable: &dyn Identifiable = reflect_identifiable.get(value.as_reflect()).unwrap();
assert_eq!(identifiable.id(), 123);
}
// Lastly, while dynamic types are commonly generated via reflection methods like
// `Reflect::clone_value` or via the reflection deserializers,
// `PartialReflect::clone_value` or via the reflection deserializers,
// you can also construct them manually.
let mut my_dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
@ -144,9 +149,13 @@ fn main() {
assert_eq!(my_list, vec![1, 2, 3]);
// And if you want it to actually proxy a type, you can configure it to do that as well:
assert!(!my_dynamic_list.as_reflect().represents::<Vec<u32>>());
assert!(!my_dynamic_list
.as_partial_reflect()
.represents::<Vec<u32>>());
my_dynamic_list.set_represented_type(Some(<Vec<u32>>::type_info()));
assert!(my_dynamic_list.as_reflect().represents::<Vec<u32>>());
assert!(my_dynamic_list
.as_partial_reflect()
.represents::<Vec<u32>>());
// ============================= REFERENCE ============================= //
// For reference, here are all the available dynamic types:

View file

@ -10,7 +10,7 @@ use bevy::reflect::func::{
ArgList, DynamicClosure, DynamicClosureMut, DynamicFunction, FunctionError, FunctionInfo,
IntoClosure, IntoClosureMut, IntoFunction, Return,
};
use bevy::reflect::Reflect;
use bevy::reflect::{PartialReflect, Reflect};
// Note that the `dbg!` invocations are used purely for demonstration purposes
// and are not strictly necessary for the example to work.
@ -52,8 +52,8 @@ fn main() {
// The `Return` value can be pattern matched or unwrapped to get the underlying reflection data.
// For the sake of brevity, we'll just unwrap it here and downcast it to the expected type of `i32`.
let value: Box<dyn Reflect> = return_value.unwrap_owned();
assert_eq!(value.take::<i32>().unwrap(), 4);
let value: Box<dyn PartialReflect> = return_value.unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 4);
// The same can also be done for closures that capture references to their environment.
// Closures that capture their environment immutably can be converted into a `DynamicClosure`
@ -64,8 +64,8 @@ fn main() {
let function: DynamicClosure = dbg!(clamp.into_closure());
let args = dbg!(ArgList::new().push_owned(2_i32));
let return_value = dbg!(function.call(args).unwrap());
let value: Box<dyn Reflect> = return_value.unwrap_owned();
assert_eq!(value.take::<i32>().unwrap(), 5);
let value: Box<dyn PartialReflect> = return_value.unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 5);
// We can also handle closures that capture their environment mutably
// using the `IntoClosureMut` trait.
@ -112,8 +112,8 @@ fn main() {
let get_value = dbg!(Data::get_value.into_function());
let args = dbg!(ArgList::new().push_ref(&data));
let return_value = dbg!(get_value.call(args).unwrap());
let value: &dyn Reflect = return_value.unwrap_ref();
assert_eq!(value.downcast_ref::<String>().unwrap(), "Hello, world!");
let value: &dyn PartialReflect = return_value.unwrap_ref();
assert_eq!(value.try_downcast_ref::<String>().unwrap(), "Hello, world!");
// Lastly, for more complex use cases, you can always create a custom `DynamicFunction` manually.
// This is useful for functions that can't be converted via the `IntoFunction` trait.
@ -172,9 +172,9 @@ fn main() {
let args = dbg!(ArgList::new().push_owned(5_i32).push_mut(&mut container));
let value = dbg!(get_or_insert_function.call(args).unwrap()).unwrap_ref();
assert_eq!(value.downcast_ref::<i32>(), Some(&5));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&5));
let args = dbg!(ArgList::new().push_owned(500_i32).push_mut(&mut container));
let value = dbg!(get_or_insert_function.call(args).unwrap()).unwrap_ref();
assert_eq!(value.downcast_ref::<i32>(), Some(&5));
assert_eq!(value.try_downcast_ref::<i32>(), Some(&5));
}

View file

@ -8,7 +8,7 @@ use bevy::{
prelude::*,
reflect::{
serde::{ReflectDeserializer, ReflectSerializer},
DynamicStruct,
DynamicStruct, PartialReflect,
},
};
use serde::de::DeserializeSeed;
@ -65,13 +65,20 @@ fn setup(type_registry: Res<AppTypeRegistry>) {
assert_eq!(value.a, 2);
assert_eq!(*value.get_field::<usize>("a").unwrap(), 2);
// You can also get the &dyn Reflect value of a field like this
// You can also get the `&dyn PartialReflect` value of a field like this
let field = value.field("a").unwrap();
// you can downcast Reflect values like this:
assert_eq!(*field.downcast_ref::<usize>().unwrap(), 2);
// But values introspected via `PartialReflect` will not return `dyn Reflect` trait objects
// (even if the containing type does implement `Reflect`), so we need to convert them:
let fully_reflected_field = field.try_as_reflect().unwrap();
// DynamicStruct also implements the `Struct` and `Reflect` traits.
// Now, you can downcast your `Reflect` value like this:
assert_eq!(*fully_reflected_field.downcast_ref::<usize>().unwrap(), 2);
// For this specific case, we also support the shortcut `try_downcast_ref`:
assert_eq!(*field.try_downcast_ref::<usize>().unwrap(), 2);
// `DynamicStruct` also implements the `Struct` and `Reflect` traits.
let mut patch = DynamicStruct::default();
patch.insert("a", 4usize);
@ -94,10 +101,14 @@ fn setup(type_registry: Res<AppTypeRegistry>) {
let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap();
let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
// Deserializing returns a Box<dyn Reflect> value. Generally, deserializing a value will return
// the "dynamic" variant of a type. For example, deserializing a struct will return the
// DynamicStruct type. "Value types" will be deserialized as themselves.
let _deserialized_struct = reflect_value.downcast_ref::<DynamicStruct>();
// Deserializing returns a `Box<dyn PartialReflect>` value.
// Generally, deserializing a value will return the "dynamic" variant of a type.
// For example, deserializing a struct will return the DynamicStruct type.
// "Value types" will be deserialized as themselves.
assert_eq!(
reflect_value.reflect_type_path(),
DynamicStruct::type_path(),
);
// Reflect has its own `partial_eq` implementation, named `reflect_partial_eq`. This behaves
// like normal `partial_eq`, but it treats "dynamic" and "non-dynamic" types the same. The

View file

@ -4,7 +4,7 @@
use bevy::{
prelude::*,
reflect::{DynamicList, ReflectRef},
reflect::{DynamicList, PartialReflect, ReflectRef},
utils::HashMap,
};
use serde::{Deserialize, Serialize};
@ -42,8 +42,9 @@ enum D {
}
/// Reflect has "built in" support for some common traits like `PartialEq`, `Hash`, and `Serialize`.
/// These are exposed via methods like `Reflect::reflect_hash()`, `Reflect::reflect_partial_eq()`, and
/// `Reflect::serializable()`. You can force these implementations to use the actual trait
/// These are exposed via methods like `PartialReflect::reflect_hash()`,
/// `PartialReflect::reflect_partial_eq()`, and `PartialReflect::serializable()`.
/// You can force these implementations to use the actual trait
/// implementations (instead of their defaults) like this:
#[derive(Reflect, Hash, Serialize, PartialEq, Eq)]
#[reflect(Hash, Serialize, PartialEq)]