reflection_types/reflection_types.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#![allow(clippy::match_same_arms)]
//! This example illustrates how reflection works for simple data structures, like
//! structs, tuples and vectors.
use bevy::{
prelude::*,
reflect::{DynamicList, PartialReflect, ReflectRef},
utils::HashMap,
};
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)]
#[allow(dead_code)]
enum D {
A,
B(usize),
C { value: f32 },
}
/// Reflect has "built in" support for some common traits like `PartialEq`, `Hash`, and `Serialize`.
///
/// 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)]
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`, `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, Serialize, Deserialize)]
#[allow(dead_code)]
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(_) => {}
}
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]);
}