bevy_ecs/reflect/
mod.rs

1//! Types that enable reflection support.
2
3use std::any::TypeId;
4use std::ops::{Deref, DerefMut};
5
6use crate as bevy_ecs;
7use crate::{system::Resource, world::World};
8use bevy_reflect::std_traits::ReflectDefault;
9use bevy_reflect::{Reflect, ReflectFromReflect, TypeRegistry, TypeRegistryArc};
10
11mod bundle;
12mod component;
13mod entity_commands;
14mod from_world;
15mod map_entities;
16mod resource;
17
18pub use bundle::{ReflectBundle, ReflectBundleFns};
19pub use component::{ReflectComponent, ReflectComponentFns};
20pub use entity_commands::ReflectCommandExt;
21pub use from_world::{ReflectFromWorld, ReflectFromWorldFns};
22pub use map_entities::{ReflectMapEntities, ReflectMapEntitiesResource};
23pub use resource::{ReflectResource, ReflectResourceFns};
24
25/// A [`Resource`] storing [`TypeRegistry`] for
26/// type registrations relevant to a whole app.
27#[derive(Resource, Clone, Default)]
28pub struct AppTypeRegistry(pub TypeRegistryArc);
29
30impl Deref for AppTypeRegistry {
31    type Target = TypeRegistryArc;
32
33    #[inline]
34    fn deref(&self) -> &Self::Target {
35        &self.0
36    }
37}
38
39impl DerefMut for AppTypeRegistry {
40    #[inline]
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        &mut self.0
43    }
44}
45
46/// Creates a `T` from a `&dyn Reflect`.
47///
48/// This will try the following strategies, in this order:
49///
50/// - use the reflected `FromReflect`, if it's present and doesn't fail;
51/// - use the reflected `Default`, if it's present, and then call `apply` on the result;
52/// - use the reflected `FromWorld`, just like the `Default`.
53///
54/// The first one that is present and doesn't fail will be used.
55///
56/// # Panics
57///
58/// If any strategy produces a `Box<dyn Reflect>` that doesn't store a value of type `T`
59/// this method will panic.
60///
61/// If none of the strategies succeed, this method will panic.
62fn from_reflect_with_fallback<T: Reflect>(
63    reflected: &dyn Reflect,
64    world: &mut World,
65    registry: &TypeRegistry,
66) -> T {
67    fn different_type_error<T>(reflected: &str) -> ! {
68        panic!(
69            "The registration for the reflected `{}` trait for the type `{}` produced \
70            a value of a different type",
71            reflected,
72            // FIXME: once we have unique reflect, use `TypePath`.
73            std::any::type_name::<T>(),
74        );
75    }
76
77    // First, try `FromReflect`. This is handled differently from the others because
78    // it doesn't need a subsequent `apply` and may fail.
79    if let Some(reflect_from_reflect) =
80        registry.get_type_data::<ReflectFromReflect>(TypeId::of::<T>())
81    {
82        // If it fails it's ok, we can continue checking `Default` and `FromWorld`.
83        if let Some(value) = reflect_from_reflect.from_reflect(reflected) {
84            return value
85                .take::<T>()
86                .unwrap_or_else(|_| different_type_error::<T>("FromReflect"));
87        }
88    }
89
90    // Create an instance of `T` using either the reflected `Default` or `FromWorld`.
91    let mut value = if let Some(reflect_default) =
92        registry.get_type_data::<ReflectDefault>(TypeId::of::<T>())
93    {
94        reflect_default
95            .default()
96            .take::<T>()
97            .unwrap_or_else(|_| different_type_error::<T>("Default"))
98    } else if let Some(reflect_from_world) =
99        registry.get_type_data::<ReflectFromWorld>(TypeId::of::<T>())
100    {
101        reflect_from_world
102            .from_world(world)
103            .take::<T>()
104            .unwrap_or_else(|_| different_type_error::<T>("FromWorld"))
105    } else {
106        panic!(
107            "Couldn't create an instance of `{}` using the reflected `FromReflect`, \
108            `Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
109            or `#[reflect(FromWorld)]`?",
110            // FIXME: once we have unique reflect, use `TypePath`.
111            std::any::type_name::<T>(),
112        );
113    };
114
115    value.apply(reflected);
116    value
117}