Skip to content

Commit a8dc9c3

Browse files
committed
section: FromReflect Ergonomics
1 parent 84cab00 commit a8dc9c3

File tree

1 file changed

+58
-3
lines changed
  • content/news/2023-07-07-bevy-0.11

1 file changed

+58
-3
lines changed

content/news/2023-07-07-bevy-0.11/index.md

+58-3
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,66 @@ Since our last release a few months ago we've added a _ton_ of new features, bug
1717

1818
* **Feature**: description
1919

20-
## Feature
20+
## `FromReflect` Ergonomics
2121

22-
<div class="release-feature-authors">authors: @todo</div>
22+
<div class="release-feature-authors">authors: @MrGVSV</div>
2323

24-
Description
24+
Bevy's [reflection API] commonly passes around data using type-erased `dyn Reflect` trait objects.
25+
This can usually be downcast back to its concrete type using `<dyn Reflect>::downcast_ref::<T>`;
26+
however, this doesn't work if the underlying data has been converted to a "dynamic" representation
27+
(e.g. `DynamicStruct` for struct types, `DynamicList` for list types, etc.).
28+
29+
```rust
30+
let data: Vec<i32> = vec![1, 2, 3];
31+
32+
let reflect: &dyn Reflect = &data;
33+
let cloned: Box<dyn Reflect> = reflect.clone_value();
34+
35+
// `reflect` really is a `Vec<i32>`
36+
assert!(reflect.is::<Vec<i32>>());
37+
assert!(reflect.represents::<Vec<i32>>());
38+
39+
// `cloned` is a `DynamicList`, but represents a `Vec<i32>`
40+
assert!(cloned.is::<DynamicList>());
41+
assert!(cloned.represents::<Vec<i32>>());
42+
43+
// `cloned` is equivalent to the original `reflect`, despite not being a `Vec<i32>`
44+
assert!(cloned.reflect_partial_eq(reflect).unwrap_or_default());
45+
```
46+
47+
To account for this, the [`FromReflect`] trait can be used to convert any `dyn Reflect` trait object
48+
back into its concrete type— whether it is actually that type or a dynamic representation of it.
49+
And it can even be called dynamically using the [`ReflectFromReflect`] type data.
50+
51+
Before 0.11, users had to be manually derive `FromReflect` for every type that needed it,
52+
as well as manually register the `ReflectFromReflect` type data.
53+
This made it cumbersome to use and also meant that it was often forgotten about,
54+
resulting in reflection conversions difficulties for users downstream.
55+
56+
Now in 0.11, `FromReflect` is automatically derived and `ReflectFromReflect` is automatically registered for all types that derive `Reflect`.
57+
This means most types will be `FromReflect`-capable by default,
58+
thus reducing boilerplate and empowering logic centered around `FromReflect`.
59+
60+
Users can still opt out of this behavior by adding the [`#[reflect(from_reflect = false)]`][from_reflect = false] attribute to their type.
61+
62+
```rust
63+
#[derive(Reflect)]
64+
struct Foo;
65+
66+
#[derive(Reflect)]
67+
#[reflect(from_reflect = false)]
68+
struct Bar;
69+
70+
fn test<T: FromReflect>(value: T) {}
71+
72+
test(Foo); // <-- OK!
73+
test(Bar); // <-- ERROR! `Bar` does not implement trait `FromReflect`
74+
```
75+
76+
[reflection API]: https://docs.rs/bevy_reflect/latest/bevy_reflect/index.html
77+
[`FromReflect`]: https://docs.rs/bevy_reflect/latest/bevy_reflect/trait.FromReflect.html
78+
[`ReflectFromReflect`]: https://docs.rs/bevy_reflect/latest/bevy_reflect/struct.ReflectFromReflect.html
79+
[from_reflect = false]: https://docs.rs/bevy_reflect/latest/bevy_reflect/derive.Reflect.html#reflectfrom_reflect--false
2580

2681
## <a name="what-s-next"></a>What's Next?
2782

0 commit comments

Comments
 (0)