Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
//! Demonstrates how to register and access custom attributes on reflected types.
use bevy::reflect::{Reflect, TypeInfo, Typed};
use std::{any::TypeId, ops::RangeInclusive};
fn main() {
// Bevy supports statically registering custom attribute data on reflected types,
// which can then be accessed at runtime via the type's `TypeInfo`.
// Attributes are registered using the `#[reflect(@...)]` syntax,
// where the `...` is any expression that resolves to a value which implements `Reflect`.
// Note that these attributes are stored based on their type:
// if two attributes have the same type, the second one will overwrite the first.
// Here is an example of registering custom attributes on a type:
#[derive(Reflect)]
struct Slider {
#[reflect(@RangeInclusive::<f32>::new(0.0, 1.0))]
// Alternatively, we could have used the `0.0..=1.0` syntax,
// but remember to ensure the type is the one you want!
#[reflect(@0.0..=1.0_f32)]
value: f32,
}
// Now, we can access the custom attributes at runtime:
let TypeInfo::Struct(type_info) = Slider::type_info() else {
panic!("expected struct");
};
let field = type_info.field("value").unwrap();
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
assert_eq!(*range, 0.0..=1.0);
// And remember that our attributes can be any type that implements `Reflect`:
#[derive(Reflect)]
struct Required;
#[derive(Reflect, PartialEq, Debug)]
struct Tooltip(String);
impl Tooltip {
fn new(text: &str) -> Self {
Self(text.to_string())
}
}
#[derive(Reflect)]
#[reflect(@Required, @Tooltip::new("An ID is required!"))]
struct Id(u8);
let TypeInfo::TupleStruct(type_info) = Id::type_info() else {
panic!("expected struct");
};
// We can check if an attribute simply exists on our type:
assert!(type_info.has_attribute::<Required>());
// We can also get attribute data dynamically:
let some_type_id = TypeId::of::<Tooltip>();
let tooltip: &dyn Reflect = type_info.get_attribute_by_id(some_type_id).unwrap();
assert_eq!(
tooltip.downcast_ref::<Tooltip>(),
Some(&Tooltip::new("An ID is required!"))
);
// And again, attributes of the same type will overwrite each other:
#[derive(Reflect)]
enum Status {
// This will result in `false` being stored:
#[reflect(@true)]
#[reflect(@false)]
Disabled,
// This will result in `true` being stored:
#[reflect(@false)]
#[reflect(@true)]
Enabled,
}
let TypeInfo::Enum(type_info) = Status::type_info() else {
panic!("expected enum");
};
let disabled = type_info.variant("Disabled").unwrap();
assert!(!disabled.get_attribute::<bool>().unwrap());
let enabled = type_info.variant("Enabled").unwrap();
assert!(enabled.get_attribute::<bool>().unwrap());
}

View File

@@ -0,0 +1,274 @@
//! This example demonstrates the use of dynamic types in Bevy's reflection system.
use bevy::reflect::{
reflect_trait, serde::TypedReflectDeserializer, std_traits::ReflectDefault, DynamicArray,
DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
DynamicTupleStruct, DynamicVariant, FromReflect, PartialReflect, Reflect, ReflectFromReflect,
Set, TypeRegistry, Typed,
};
use serde::de::DeserializeSeed;
use std::collections::{HashMap, HashSet};
fn main() {
#[derive(Reflect, Default, PartialEq, Debug)]
#[reflect(Identifiable, Default)]
struct Player {
id: u32,
}
#[reflect_trait]
trait Identifiable {
fn id(&self) -> u32;
}
impl Identifiable for Player {
fn id(&self) -> u32 {
self.id
}
}
// Normally, when instantiating a type, you get back exactly that type.
// This is because the type is known at compile time.
// We call this the "concrete" or "canonical" type.
let player: Player = Player { id: 123 };
// 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);
// 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());
// We can attempt to clone our value using `PartialReflect::reflect_clone`.
// This will recursively call `PartialReflect::reflect_clone` on all fields of the type.
// Or, if we had registered `ReflectClone` using `#[reflect(Clone)]`, it would simply call `Clone::clone` directly.
let cloned: Box<dyn Reflect> = reflected.reflect_clone().unwrap();
assert_eq!(cloned.downcast_ref::<Player>(), Some(&Player { id: 123 }));
// Another way we can "clone" our data is by converting it to a dynamic type.
// Notice here we bind it as a `dyn PartialReflect` instead of `dyn Reflect`.
// This is because it returns a dynamic type that simply represents the original type.
// In this case, because `Player` is a struct, it will return a `DynamicStruct`.
let dynamic: Box<dyn PartialReflect> = reflected.to_dynamic();
assert!(dynamic.is_dynamic());
// And if we try to convert it back to a `dyn Reflect` trait object, we'll get `None`.
// Dynamic types cannot be directly cast to `dyn Reflect` trait objects.
assert!(dynamic.try_as_reflect().is_none());
// Generally dynamic types are used to represent (or "proxy") the original type,
// so that we can continue to access its fields and overall structure.
let dynamic_ref = dynamic.reflect_ref().as_struct().unwrap();
let id = dynamic_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
// access to the actual type. This is how the reflection deserializers work.
// They generally can't know how to construct a type ahead of time,
// so they instead build and return these dynamic representations.
let input = "(id: 123)";
let mut registry = TypeRegistry::default();
registry.register::<Player>();
let registration = registry.get(std::any::TypeId::of::<Player>()).unwrap();
let deserialized = TypedReflectDeserializer::new(registration, &registry)
.deserialize(&mut ron::Deserializer::from_str(input).unwrap())
.unwrap();
// Our deserialized output is a `DynamicStruct` that proxies/represents a `Player`.
assert!(deserialized.represents::<Player>());
// And while this does allow us to access the fields and structure of the type,
// there may be instances where we need the actual type.
// For example, if we want to convert our `dyn Reflect` into a `dyn Identifiable`,
// we can't use the `DynamicStruct` proxy.
let reflect_identifiable = registration
.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!(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 `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_ref());
assert_eq!(value.id, 123);
// If you don't know the type at compile time, you need a dynamic way of constructing
// an instance of the type. One such way is to use the `ReflectDefault` type data.
let reflect_default = registration
.data::<ReflectDefault>()
.expect("`ReflectDefault` should be registered");
let mut value: Box<dyn Reflect> = reflect_default.default();
value.apply(deserialized.as_ref());
let identifiable: &dyn Identifiable = reflect_identifiable.get(value.as_reflect()).unwrap();
assert_eq!(identifiable.id(), 123);
}
// 2. Using `FromReflect`
{
// 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_ref()).unwrap();
assert_eq!(value.id, 123);
// If you don't know the type at compile time, you can use the `ReflectFromReflect` type data
// to perform the conversion dynamically.
let reflect_from_reflect = registration
.data::<ReflectFromReflect>()
.expect("`ReflectFromReflect` should be registered");
let value: Box<dyn Reflect> = reflect_from_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
// `PartialReflect::to_dynamic` or via the reflection deserializers,
// you can also construct them manually.
let mut my_dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
// This is useful when you just need to apply some subset of changes to a type.
let mut my_list: Vec<u32> = Vec::new();
my_list.apply(&my_dynamic_list);
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_partial_reflect()
.represents::<Vec<u32>>());
my_dynamic_list.set_represented_type(Some(<Vec<u32>>::type_info()));
assert!(my_dynamic_list
.as_partial_reflect()
.represents::<Vec<u32>>());
// ============================= REFERENCE ============================= //
// For reference, here are all the available dynamic types:
// 1. `DynamicTuple`
{
let mut dynamic_tuple = DynamicTuple::default();
dynamic_tuple.insert(1u32);
dynamic_tuple.insert(2u32);
dynamic_tuple.insert(3u32);
let mut my_tuple: (u32, u32, u32) = (0, 0, 0);
my_tuple.apply(&dynamic_tuple);
assert_eq!(my_tuple, (1, 2, 3));
}
// 2. `DynamicArray`
{
let dynamic_array = DynamicArray::from_iter([1u32, 2u32, 3u32]);
let mut my_array = [0u32; 3];
my_array.apply(&dynamic_array);
assert_eq!(my_array, [1, 2, 3]);
}
// 3. `DynamicList`
{
let dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
let mut my_list: Vec<u32> = Vec::new();
my_list.apply(&dynamic_list);
assert_eq!(my_list, vec![1, 2, 3]);
}
// 4. `DynamicSet`
{
let mut dynamic_set = DynamicSet::from_iter(["x", "y", "z"]);
assert!(dynamic_set.contains(&"x"));
dynamic_set.remove(&"y");
let mut my_set: HashSet<&str> = HashSet::default();
my_set.apply(&dynamic_set);
assert_eq!(my_set, HashSet::from_iter(["x", "z"]));
}
// 5. `DynamicMap`
{
let dynamic_map = DynamicMap::from_iter([("x", 1u32), ("y", 2u32), ("z", 3u32)]);
let mut my_map: HashMap<&str, u32> = HashMap::default();
my_map.apply(&dynamic_map);
assert_eq!(my_map.get("x"), Some(&1));
assert_eq!(my_map.get("y"), Some(&2));
assert_eq!(my_map.get("z"), Some(&3));
}
// 6. `DynamicStruct`
{
#[derive(Reflect, Default, Debug, PartialEq)]
struct MyStruct {
x: u32,
y: u32,
z: u32,
}
let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.insert("x", 1u32);
dynamic_struct.insert("y", 2u32);
dynamic_struct.insert("z", 3u32);
let mut my_struct = MyStruct::default();
my_struct.apply(&dynamic_struct);
assert_eq!(my_struct, MyStruct { x: 1, y: 2, z: 3 });
}
// 7. `DynamicTupleStruct`
{
#[derive(Reflect, Default, Debug, PartialEq)]
struct MyTupleStruct(u32, u32, u32);
let mut dynamic_tuple_struct = DynamicTupleStruct::default();
dynamic_tuple_struct.insert(1u32);
dynamic_tuple_struct.insert(2u32);
dynamic_tuple_struct.insert(3u32);
let mut my_tuple_struct = MyTupleStruct::default();
my_tuple_struct.apply(&dynamic_tuple_struct);
assert_eq!(my_tuple_struct, MyTupleStruct(1, 2, 3));
}
// 8. `DynamicEnum`
{
#[derive(Reflect, Default, Debug, PartialEq)]
enum MyEnum {
#[default]
Empty,
Xyz(u32, u32, u32),
}
let mut values = DynamicTuple::default();
values.insert(1u32);
values.insert(2u32);
values.insert(3u32);
let dynamic_variant = DynamicVariant::Tuple(values);
let dynamic_enum = DynamicEnum::new("Xyz", dynamic_variant);
let mut my_enum = MyEnum::default();
my_enum.apply(&dynamic_enum);
assert_eq!(my_enum, MyEnum::Xyz(1, 2, 3));
}
}

View File

@@ -0,0 +1,220 @@
//! This example demonstrates how functions can be called dynamically using reflection.
//!
//! Function reflection is useful for calling regular Rust functions in a dynamic context,
//! where the types of arguments, return values, and even the function itself aren't known at compile time.
//!
//! This can be used for things like adding scripting support to your application,
//! processing deserialized reflection data, or even just storing type-erased versions of your functions.
use bevy::reflect::{
func::{
ArgList, DynamicFunction, DynamicFunctionMut, FunctionResult, IntoFunction,
IntoFunctionMut, Return, SignatureInfo,
},
PartialReflect, Reflect,
};
// Note that the `dbg!` invocations are used purely for demonstration purposes
// and are not strictly necessary for the example to work.
fn main() {
// There are times when it may be helpful to store a function away for later.
// In Rust, we can do this by storing either a function pointer or a function trait object.
// For example, say we wanted to store the following function:
fn add(left: i32, right: i32) -> i32 {
left + right
}
// We could store it as either of the following:
let fn_pointer: fn(i32, i32) -> i32 = add;
let fn_trait_object: Box<dyn Fn(i32, i32) -> i32> = Box::new(add);
// And we can call them like so:
let result = fn_pointer(2, 2);
assert_eq!(result, 4);
let result = fn_trait_object(2, 2);
assert_eq!(result, 4);
// However, you'll notice that we have to know the types of the arguments and return value at compile time.
// This means there's not really a way to store or call these functions dynamically at runtime.
// Luckily, Bevy's reflection crate comes with a set of tools for doing just that!
// We do this by first converting our function into the reflection-based `DynamicFunction` type
// using the `IntoFunction` trait.
let function: DynamicFunction<'static> = dbg!(add.into_function());
// This time, you'll notice that `DynamicFunction` doesn't take any information about the function's arguments or return value.
// This is because `DynamicFunction` checks the types of the arguments and return value at runtime.
// Now we can generate a list of arguments:
let args: ArgList = dbg!(ArgList::new().with_owned(2_i32).with_owned(2_i32));
// And finally, we can call the function.
// This returns a `Result` indicating whether the function was called successfully.
// For now, we'll just unwrap it to get our `Return` value,
// which is an enum containing the function's return value.
let return_value: Return = dbg!(function.call(args).unwrap());
// 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 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 `DynamicFunction`
// using the `IntoFunction` trait.
let minimum = 5;
let clamp = |value: i32| value.max(minimum);
let function: DynamicFunction = dbg!(clamp.into_function());
let args = dbg!(ArgList::new().with_owned(2_i32));
let return_value = dbg!(function.call(args).unwrap());
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 `IntoFunctionMut` trait.
let mut count = 0;
let increment = |amount: i32| count += amount;
let closure: DynamicFunctionMut = dbg!(increment.into_function_mut());
let args = dbg!(ArgList::new().with_owned(5_i32));
// Because `DynamicFunctionMut` mutably borrows `total`,
// it will need to be dropped before `total` can be accessed again.
// This can be done manually with `drop(closure)` or by using the `DynamicFunctionMut::call_once` method.
dbg!(closure.call_once(args).unwrap());
assert_eq!(count, 5);
// Generic functions can also be converted into a `DynamicFunction`,
// however, they will need to be manually monomorphized first.
fn stringify<T: ToString>(value: T) -> String {
value.to_string()
}
// We have to manually specify the concrete generic type we want to use.
let function = stringify::<i32>.into_function();
let args = ArgList::new().with_owned(123_i32);
let return_value = function.call(args).unwrap();
let value: Box<dyn PartialReflect> = return_value.unwrap_owned();
assert_eq!(value.try_take::<String>().unwrap(), "123");
// To make things a little easier, we can also "overload" functions.
// This makes it so that a single `DynamicFunction` can represent multiple functions,
// and the correct one is chosen based on the types of the arguments.
// Each function overload must have a unique argument signature.
let function = stringify::<i32>
.into_function()
.with_overload(stringify::<f32>);
// Now our `function` accepts both `i32` and `f32` arguments.
let args = ArgList::new().with_owned(1.23_f32);
let return_value = function.call(args).unwrap();
let value: Box<dyn PartialReflect> = return_value.unwrap_owned();
assert_eq!(value.try_take::<String>().unwrap(), "1.23");
// Function overloading even allows us to have a variable number of arguments.
let function = (|| 0)
.into_function()
.with_overload(|a: i32| a)
.with_overload(|a: i32, b: i32| a + b)
.with_overload(|a: i32, b: i32, c: i32| a + b + c);
let args = ArgList::new()
.with_owned(1_i32)
.with_owned(2_i32)
.with_owned(3_i32);
let return_value = function.call(args).unwrap();
let value: Box<dyn PartialReflect> = return_value.unwrap_owned();
assert_eq!(value.try_take::<i32>().unwrap(), 6);
// As stated earlier, `IntoFunction` works for many kinds of simple functions.
// Functions with non-reflectable arguments or return values may not be able to be converted.
// Generic functions are also not supported (unless manually monomorphized like `foo::<i32>.into_function()`).
// Additionally, the lifetime of the return value is tied to the lifetime of the first argument.
// However, this means that many methods (i.e. functions with a `self` parameter) are also supported:
#[derive(Reflect, Default)]
struct Data {
value: String,
}
impl Data {
fn set_value(&mut self, value: String) {
self.value = value;
}
// Note that only `&'static str` implements `Reflect`.
// To get around this limitation we can use `&String` instead.
fn get_value(&self) -> &String {
&self.value
}
}
let mut data = Data::default();
let set_value = dbg!(Data::set_value.into_function());
let args = dbg!(ArgList::new().with_mut(&mut data)).with_owned(String::from("Hello, world!"));
dbg!(set_value.call(args).unwrap());
assert_eq!(data.value, "Hello, world!");
let get_value = dbg!(Data::get_value.into_function());
let args = dbg!(ArgList::new().with_ref(&data));
let return_value = dbg!(get_value.call(args).unwrap());
let value: &dyn PartialReflect = return_value.unwrap_ref();
assert_eq!(value.try_downcast_ref::<String>().unwrap(), "Hello, world!");
// 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.
// For example, this function doesn't implement `IntoFunction` due to the fact that
// the lifetime of the return value is not tied to the lifetime of the first argument.
fn get_or_insert(value: i32, container: &mut Option<i32>) -> &i32 {
if container.is_none() {
*container = Some(value);
}
container.as_ref().unwrap()
}
let get_or_insert_function = dbg!(DynamicFunction::new(
|mut args: ArgList| -> FunctionResult {
// The `ArgList` contains the arguments in the order they were pushed.
// The `DynamicFunction` will validate that the list contains
// exactly the number of arguments we expect.
// We can retrieve them out in order (note that this modifies the `ArgList`):
let value = args.take::<i32>()?;
let container = args.take::<&mut Option<i32>>()?;
// We could have also done the following to make use of type inference:
// let value = args.take_owned()?;
// let container = args.take_mut()?;
Ok(Return::Ref(get_or_insert(value, container)))
},
// Functions can be either anonymous or named.
// It's good practice, though, to try and name your functions whenever possible.
// This makes it easier to debug and is also required for function registration.
// We can either give it a custom name or use the function's type name as
// derived from `std::any::type_name_of_val`.
SignatureInfo::named(std::any::type_name_of_val(&get_or_insert))
// We can always change the name if needed.
// It's a good idea to also ensure that the name is unique,
// such as by using its type name or by prefixing it with your crate name.
.with_name("my_crate::get_or_insert")
// Since our function takes arguments, we should provide that argument information.
// This is used to validate arguments when calling the function.
// And it aids consumers of the function with their own validation and debugging.
// Arguments should be provided in the order they are defined in the function.
.with_arg::<i32>("value")
.with_arg::<&mut Option<i32>>("container")
// We can provide return information as well.
.with_return::<&i32>(),
));
let mut container: Option<i32> = None;
let args = dbg!(ArgList::new().with_owned(5_i32).with_mut(&mut container));
let value = dbg!(get_or_insert_function.call(args).unwrap()).unwrap_ref();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&5));
let args = dbg!(ArgList::new().with_owned(500_i32).with_mut(&mut container));
let value = dbg!(get_or_insert_function.call(args).unwrap()).unwrap_ref();
assert_eq!(value.try_downcast_ref::<i32>(), Some(&5));
}

View File

@@ -0,0 +1,33 @@
//! Demonstrates how reflection is used with generic Rust types.
use bevy::prelude::*;
use std::any::TypeId;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// You must manually register each instance of a generic type
.register_type::<MyType<u32>>()
.add_systems(Startup, setup)
.run();
}
/// The `#[derive(Reflect)]` macro will automatically add any required bounds to `T`,
/// such as `Reflect` and `GetTypeRegistration`.
#[derive(Reflect)]
struct MyType<T> {
value: T,
}
fn setup(type_registry: Res<AppTypeRegistry>) {
let type_registry = type_registry.read();
let registration = type_registry.get(TypeId::of::<MyType<u32>>()).unwrap();
info!(
"Registration for {} exists",
registration.type_info().type_path(),
);
// MyType<String> was not manually registered, so it does not exist
assert!(type_registry.get(TypeId::of::<MyType<String>>()).is_none());
}

View File

@@ -0,0 +1,121 @@
//! Illustrates how "reflection" works in Bevy.
//!
//! Reflection provides a way to dynamically interact with Rust types, such as accessing fields
//! by their string name. Reflection is a core part of Bevy and enables a number of interesting
//! features (like scenes).
use bevy::{
prelude::*,
reflect::{
serde::{ReflectDeserializer, ReflectSerializer},
DynamicStruct, PartialReflect,
},
};
use serde::de::DeserializeSeed;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// Bar will be automatically registered as it's a dependency of Foo
.register_type::<Foo>()
.add_systems(Startup, setup)
.run();
}
/// Deriving `Reflect` implements the relevant reflection traits. In this case, it implements the
/// `Reflect` trait and the `Struct` trait `derive(Reflect)` assumes that all fields also implement
/// Reflect.
///
/// All fields in a reflected item will need to be `Reflect` as well. You can opt a field out of
/// reflection by using the `#[reflect(ignore)]` attribute.
/// If you choose to ignore a field, you need to let the automatically-derived `FromReflect` implementation
/// how to handle the field.
/// To do this, you can either define a `#[reflect(default = "...")]` attribute on the ignored field, or
/// opt-out of `FromReflect`'s auto-derive using the `#[reflect(from_reflect = false)]` attribute.
#[derive(Reflect)]
#[reflect(from_reflect = false)]
pub struct Foo {
a: usize,
nested: Bar,
#[reflect(ignore)]
_ignored: NonReflectedValue,
}
/// This `Bar` type is used in the `nested` field of the `Foo` type. We must derive `Reflect` here
/// too (or ignore it)
#[derive(Reflect)]
pub struct Bar {
b: usize,
}
#[derive(Default)]
struct NonReflectedValue {
_a: usize,
}
fn setup(type_registry: Res<AppTypeRegistry>) {
let mut value = Foo {
a: 1,
_ignored: NonReflectedValue { _a: 10 },
nested: Bar { b: 8 },
};
// You can set field values like this. The type must match exactly or this will fail.
*value.get_field_mut("a").unwrap() = 2usize;
assert_eq!(value.a, 2);
assert_eq!(*value.get_field::<usize>("a").unwrap(), 2);
// You can also get the `&dyn PartialReflect` value of a field like this
let field = value.field("a").unwrap();
// 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();
// 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);
// You can "apply" Reflect implementations on top of other Reflect implementations.
// This will only set fields with the same name, and it will fail if the types don't match.
// You can use this to "patch" your types with new values.
value.apply(&patch);
assert_eq!(value.a, 4);
let type_registry = type_registry.read();
// By default, all derived `Reflect` types can be Serialized using serde. No need to derive
// Serialize!
let serializer = ReflectSerializer::new(&value, &type_registry);
let ron_string =
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
info!("{}\n", ron_string);
// Dynamic properties can be deserialized
let reflect_deserializer = ReflectDeserializer::new(&type_registry);
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 PartialReflect>` value.
// Generally, deserializing a value will return the "dynamic" variant of a type.
// For example, deserializing a struct will return the DynamicStruct type.
// "Opaque 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
// `Foo` struct and deserialized `DynamicStruct` are considered equal for this reason:
assert!(reflect_value.reflect_partial_eq(&value).unwrap());
// By "patching" `Foo` with the deserialized DynamicStruct, we can "Deserialize" Foo.
// This means we can serialize and deserialize with a single `Reflect` derive!
value.apply(&*reflect_value);
}

View File

@@ -0,0 +1,143 @@
//! This example illustrates how reflection works for simple data structures, like
//! structs, tuples and vectors.
use bevy::{
platform::collections::HashMap,
prelude::*,
reflect::{DynamicList, PartialReflect, ReflectRef},
};
use serde::{Deserialize, Serialize};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
/// Deriving reflect on a struct will implement the `Reflect` and `Struct` traits
#[derive(Reflect)]
pub struct A {
x: usize,
y: Vec<u32>,
z: HashMap<String, f32>,
}
/// Deriving reflect on a unit struct will implement the `Reflect` and `Struct` traits
#[derive(Reflect)]
pub struct B;
/// Deriving reflect on a tuple struct will implement the `Reflect` and `TupleStruct` traits
#[derive(Reflect)]
pub struct C(usize);
/// Deriving reflect on an enum will implement the `Reflect` and `Enum` traits
#[derive(Reflect)]
enum D {
A,
B(usize),
C { value: f32 },
}
/// Reflect has "built in" support for some common traits like `PartialEq`, `Hash`, and `Clone`.
///
/// These are exposed via methods like `PartialReflect::reflect_hash()`,
/// `PartialReflect::reflect_partial_eq()`, and `PartialReflect::reflect_clone()`.
/// You can force these implementations to use the actual trait
/// implementations (instead of their defaults) like this:
#[derive(Reflect, Hash, PartialEq, Clone)]
#[reflect(Hash, PartialEq, Clone)]
pub struct E {
x: usize,
}
/// By default, deriving with Reflect assumes the type is either a "struct" or an "enum".
///
/// You can tell reflect to treat your type instead as an "opaque type" by using the `#[reflect(opaque)]`.
/// It is generally a good idea to implement (and reflect) the `PartialEq` and `Clone` (optionally also `Serialize` and `Deserialize`)
/// traits on opaque types to ensure that these values behave as expected when nested in other reflected types.
#[derive(Reflect, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[reflect(opaque)]
#[reflect(PartialEq, Clone, Serialize, Deserialize)]
enum F {
X,
Y,
}
fn setup() {
let mut z = <HashMap<_, _>>::default();
z.insert("Hello".to_string(), 1.0);
let value: Box<dyn Reflect> = Box::new(A {
x: 1,
y: vec![1, 2],
z,
});
// There are a number of different "reflect traits", which each expose different operations on
// the underlying type
match value.reflect_ref() {
// `Struct` is a trait automatically implemented for structs that derive Reflect. This trait
// allows you to interact with fields via their string names or indices
ReflectRef::Struct(value) => {
info!(
"This is a 'struct' type with an 'x' value of {}",
value.get_field::<usize>("x").unwrap()
);
}
// `TupleStruct` is a trait automatically implemented for tuple structs that derive Reflect.
// This trait allows you to interact with fields via their indices
ReflectRef::TupleStruct(_) => {}
// `Tuple` is a special trait that can be manually implemented (instead of deriving
// Reflect). This exposes "tuple" operations on your type, allowing you to interact
// with fields via their indices. Tuple is automatically implemented for tuples of
// arity 12 or less.
ReflectRef::Tuple(_) => {}
// `Enum` is a trait automatically implemented for enums that derive Reflect. This trait allows you
// to interact with the current variant and its fields (if it has any)
ReflectRef::Enum(_) => {}
// `List` is a special trait that can be manually implemented (instead of deriving Reflect).
// This exposes "list" operations on your type, such as insertion. `List` is automatically
// implemented for relevant core types like Vec<T>.
ReflectRef::List(_) => {}
// `Array` is a special trait that can be manually implemented (instead of deriving Reflect).
// This exposes "array" operations on your type, such as indexing. `Array`
// is automatically implemented for relevant core types like [T; N].
ReflectRef::Array(_) => {}
// `Map` is a special trait that can be manually implemented (instead of deriving Reflect).
// This exposes "map" operations on your type, such as getting / inserting by key.
// Map is automatically implemented for relevant core types like HashMap<K, V>
ReflectRef::Map(_) => {}
// `Set` is a special trait that can be manually implemented (instead of deriving Reflect).
// This exposes "set" operations on your type, such as getting / inserting by value.
// Set is automatically implemented for relevant core types like HashSet<T>
ReflectRef::Set(_) => {}
// `Function` is a special trait that can be manually implemented (instead of deriving Reflect).
// This exposes "function" operations on your type, such as calling it with arguments.
// This trait is automatically implemented for types like DynamicFunction.
// This variant only exists if the `reflect_functions` feature is enabled.
#[cfg(feature = "reflect_functions")]
ReflectRef::Function(_) => {}
// `Opaque` types do not implement any of the other traits above. They are simply a Reflect
// implementation. Opaque is implemented for opaque types like String and Instant,
// but also include primitive types like i32, usize, and f32 (despite not technically being opaque).
ReflectRef::Opaque(_) => {}
#[expect(
clippy::allow_attributes,
reason = "`unreachable_patterns` is not always linted"
)]
#[allow(
unreachable_patterns,
reason = "This example cannot always detect when `bevy_reflect/functions` is enabled."
)]
_ => {}
}
let mut dynamic_list = DynamicList::default();
dynamic_list.push(3u32);
dynamic_list.push(4u32);
dynamic_list.push(5u32);
let mut value: A = value.take::<A>().unwrap();
value.y.apply(&dynamic_list);
assert_eq!(value.y, vec![3u32, 4u32, 5u32]);
}

View File

@@ -0,0 +1,158 @@
//! The example demonstrates what type data is, how to create it, and how to use it.
use bevy::{
prelude::*,
reflect::{FromType, TypeRegistry},
};
// It's recommended to read this example from top to bottom.
// Comments are provided to explain the code and its purpose as you go along.
fn main() {
trait Damageable {
type Health;
fn damage(&mut self, damage: Self::Health);
}
#[derive(Reflect, PartialEq, Debug)]
struct Zombie {
health: u32,
}
impl Damageable for Zombie {
type Health = u32;
fn damage(&mut self, damage: Self::Health) {
self.health -= damage;
}
}
// Let's say we have a reflected value.
// Here we know it's a `Zombie`, but for demonstration purposes let's pretend we don't.
// Pretend it's just some `Box<dyn Reflect>` value.
let mut value: Box<dyn Reflect> = Box::new(Zombie { health: 100 });
// We think `value` might contain a type that implements `Damageable`
// and now we want to call `Damageable::damage` on it.
// How can we do this without knowing in advance the concrete type is `Zombie`?
// This is where type data comes in.
// Type data is a way of associating type-specific data with a type for use in dynamic contexts.
// This type data can then be used at runtime to perform type-specific operations.
// Let's create a type data struct for `Damageable` that we can associate with `Zombie`!
// Firstly, type data must be cloneable.
#[derive(Clone)]
// Next, they are usually named with the `Reflect` prefix (we'll see why in a bit).
struct ReflectDamageable {
// Type data can contain whatever you want, but it's common to include function pointers
// to the type-specific operations you want to perform (such as trait methods).
// Just remember that we're working with `Reflect` data,
// so we can't use `Self`, generics, or associated types.
// In those cases, we'll have to use `dyn Reflect` trait objects.
damage: fn(&mut dyn Reflect, damage: Box<dyn Reflect>),
}
// Now, we can create a blanket implementation of the `FromType` trait to construct our type data
// for any type that implements `Reflect` and `Damageable`.
impl<T: Reflect + Damageable<Health: Reflect>> FromType<T> for ReflectDamageable {
fn from_type() -> Self {
Self {
damage: |reflect, damage| {
// This requires that `reflect` is `T` and not a dynamic representation like `DynamicStruct`.
// We could have the function pointer return a `Result`, but we'll just `unwrap` for simplicity.
let damageable = reflect.downcast_mut::<T>().unwrap();
let damage = damage.take::<T::Health>().unwrap();
damageable.damage(damage);
},
}
}
}
// It's also common to provide convenience methods for calling the type-specific operations.
impl ReflectDamageable {
pub fn damage(&self, reflect: &mut dyn Reflect, damage: Box<dyn Reflect>) {
(self.damage)(reflect, damage);
}
}
// With all this done, we're ready to make use of `ReflectDamageable`!
// It starts with registering our type along with its type data:
let mut registry = TypeRegistry::default();
registry.register::<Zombie>();
registry.register_type_data::<Zombie, ReflectDamageable>();
// Then at any point we can retrieve the type data from the registry:
let type_id = value.reflect_type_info().type_id();
let reflect_damageable = registry
.get_type_data::<ReflectDamageable>(type_id)
.unwrap();
// And call our method:
reflect_damageable.damage(value.as_reflect_mut(), Box::new(25u32));
assert_eq!(value.take::<Zombie>().unwrap(), Zombie { health: 75 });
// This is a simple example, but type data can be used for much more complex operations.
// Bevy also provides some useful shorthand for working with type data.
// For example, we can have the type data be automatically registered when we register the type
// by using the `#[reflect(MyTrait)]` attribute when defining our type.
#[derive(Reflect)]
// Notice that we don't need to type out `ReflectDamageable`.
// This is why we named it with the `Reflect` prefix:
// the derive macro will automatically look for a type named `ReflectDamageable` in the current scope.
#[reflect(Damageable)]
struct Skeleton {
health: u32,
}
impl Damageable for Skeleton {
type Health = u32;
fn damage(&mut self, damage: Self::Health) {
self.health -= damage;
}
}
// This will now register `Skeleton` along with its `ReflectDamageable` type data.
registry.register::<Skeleton>();
// And for object-safe traits (see https://doc.rust-lang.org/reference/items/traits.html#object-safety),
// Bevy provides a convenience macro for generating type data that converts `dyn Reflect` into `dyn MyTrait`.
#[reflect_trait]
trait Health {
fn health(&self) -> u32;
}
impl Health for Skeleton {
fn health(&self) -> u32 {
self.health
}
}
// Using the `#[reflect_trait]` macro we're able to automatically generate a `ReflectHealth` type data struct,
// which can then be registered like any other type data:
registry.register_type_data::<Skeleton, ReflectHealth>();
// Now we can use `ReflectHealth` to convert `dyn Reflect` into `dyn Health`:
let value: Box<dyn Reflect> = Box::new(Skeleton { health: 50 });
let type_id = value.reflect_type_info().type_id();
let reflect_health = registry.get_type_data::<ReflectHealth>(type_id).unwrap();
// Type data generated by `#[reflect_trait]` comes with a `get`, `get_mut`, and `get_boxed` method,
// which convert `&dyn Reflect` into `&dyn MyTrait`, `&mut dyn Reflect` into `&mut dyn MyTrait`,
// and `Box<dyn Reflect>` into `Box<dyn MyTrait>`, respectively.
let value: &dyn Health = reflect_health.get(value.as_reflect()).unwrap();
assert_eq!(value.health(), 50);
// Lastly, here's a list of some useful type data provided by Bevy that you might want to register for your types:
// - `ReflectDefault` for types that implement `Default`
// - `ReflectFromWorld` for types that implement `FromWorld`
// - `ReflectComponent` for types that implement `Component`
// - `ReflectResource` for types that implement `Resource`
// - `ReflectSerialize` for types that implement `Serialize`
// - `ReflectDeserialize` for types that implement `Deserialize`
//
// And here are some that are automatically registered by the `Reflect` derive macro:
// - `ReflectFromPtr`
// - `ReflectFromReflect` (if not `#[reflect(from_reflect = false)]`)
}