You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/inside-rust/program-management-update-2025-08.md
+14-14Lines changed: 14 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -72,17 +72,17 @@ Both have been requested for a long time and the interest is much broader than j
72
72
73
73
Reflection is a mechanism that lets your program look at any type and understand it: getting its name, fields and *their names and types* while your program is running. This is in contrast to the `derive` macro or trait bounds that are processed at compile time.
74
74
75
-
Projects like Bevy currently rely on the `derive` macros. For example, any component in its [ECS (Entity Component System)](https://bevy.org/learn/quick-start/getting-started/ecs/) must be annotated with `#[derive(Component)]`. While the usage is simple, these macros are difficult to write and debug. And the language has limitations on where they can be applied.
75
+
Projects like Bevy currently rely on the `derive` macros. For example, pretty much all its types have `derive(Reflect)` to provide dynamic field access and type inspection, serialization/deserialization and scripting. While the usage is simple, these macros are difficult to write and debug. And the language has limitations on where they can be applied.
76
76
77
77
You can only implement a trait for a type (which is what `derive` does, under the hood) if either the trait or type is *defined* in the crate you're implementing it in (this is the [orphan rule](https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type)).
78
78
79
-
So if you're writing your game and want to implement `Component` (defined in Bevy, not your crate) you could derive it for your custom type, but not e.g. for [`Duration`](https://doc.rust-lang.org/std/time/struct.Duration.html) or `[f32; 2]` because they're defined in the standard library. You have to [resort to wrapping those in your own type](https://docs.rs/bevy/latest/bevy/ecs/component/trait.Component.html#implementing-the-trait-for-foreign-types).
79
+
So if want to implement `Reflect` (defined in [bevy_reflect](https://crates.io/crates/bevy_reflect), not your crate) you could derive it for your custom type, but not e.g. for [`Duration`](https://doc.rust-lang.org/std/time/struct.Duration.html) or `[f32; 2]` because they're defined in the standard library.
80
80
81
-
This all gets very complex very quickly and no good solution exists right now. In reality, projects like Serde and Bevy often provide implementations for common standard library types (including tuples up to a limited size).
81
+
You have to create a new `enum`/`struct` that wraps that type and implement the trait yourself. This all gets very complex very quickly and no good solution exists right now.
82
82
83
-
But when a new crate comes up, it either has to implement all the useful traits in the ecosystem, convince to the ecosystem to provide the implementations for its types or be immediately less useful than the existing crates. This can lead to ecosystem stagnation.
83
+
In practice, projects like Serde and Bevy often provide implementations for common standard library types (including tuples up to a limited size). But when a new crate comes up, it either has to implement all the useful traits in the ecosystem, convince to the ecosystem to provide the implementations for its types or be immediately less useful than the existing crates. This can lead to ecosystem stagnation.
84
84
85
-
With reflection, any type could be used as a `Component` with none of the third parties (Bevy or std) having to opt in explicitly.
85
+
With reflection, a lot of this machinery would just be available on every type everywhere and everyone could use it.
86
86
87
87
[oli-obk](https://github.com/oli-obk) opened the [reflection and comptime goal](https://rust-lang.github.io/rust-project-goals/2025h2/reflection-and-comptime.html) for the 2025H2 period that will build the initial functionality and extend it later on.
88
88
@@ -137,7 +137,7 @@ Some of the efforts blocking this in the past have either been resolved or are g
137
137
138
138
I've done a lot of background reading (which made me appreciate the complexity), talked to Olivier and [Alice Cecile](https://github.com/alice-i-cecile) and [opened a design meeting on the Lang side](https://github.com/rust-lang/lang-team/issues/348) as there is a way forward now.
139
139
140
-
Olivier plans to write an RFC in the next month or so and then we'll discuss it. I'm again on the lookout for other people interested in the space (either with proposals of their own or usecases we want to make sure are heard) so I can point them to the design issue and the meeting.
140
+
The next steps are getting an RFC written and scheduling the design meeting. I'm again on the lookout for other people interested in the space (either with proposals of their own or usecases we want to make sure are heard) so I can point them to this space.
141
141
142
142
143
143
## Lori Lorusso: Foundation Director of Outreach
@@ -204,26 +204,26 @@ This is now ready for feedback from the Lang team so I've opened a [design issue
We also had a design meeting on [Field Projections][field-projections]. When you have a type behind e.g. `Box` or `Rc`, you can access its field "directly" as if the wrapper/pointer type wasn't there:
207
+
We also had a design meeting on [Field Projections][field-projections]. When you have a type behind a `&` or `&mut` reference, you can access its field "directly" as if the pointer type wasn't there:
208
208
209
209
```rust
210
210
structPosition {
211
211
x:f32,
212
212
y:f32,
213
213
}
214
214
215
-
fnmain() {
216
-
letpos=Position{ x:0.0, y:0.0 };
217
-
letboxed=Box::new(pos);
218
-
println!("x: {}, y: {}", boxed.x, boxed.y);
215
+
implPosition {
216
+
fnget_x(&self) ->&f32 {
217
+
&self.x
218
+
}
219
219
}
220
220
```
221
221
222
-
This is so common that we take it for granted, but when you write `boxed.x`, we first need to dereference `boxed` (follow the pointer to the `Position` struct in the memory) and then get its `x` field.
222
+
The language understands `Position` is behind a pointer, calculates an offset to the field `x`and gives you that pointer back.
223
223
224
-
And while this works for references and some pointer types, there's a long list of wrapper types where field access makes sense but it's not implemented because the semantics or limitations are different from the regular `Deref/DerefMut` traits. For example: `MaybeUninit<T>`, `Pin<T>`, `Cell<T>`, or the raw pointers `*const T`/`*mut T`. And of course custom types.
224
+
But there's a long list of wrapper types where field access makes sense, but it's not implemented because the semantics or limitations are different from the regular `Deref/DerefMut` traits. For example: `MaybeUninit<T>`, `Pin<P>`, `Cell<T>`, or the raw pointers `*const T`/`*mut T`. And of course custom types.
225
225
226
-
Linux uses pinned values (`Pin<T>`, values that can't move around in memory) all over the place and there are several crates that provide access to the underlying fields of a pinned struct (e.g. [pin-project](https://crates.io/crates/pin-project)).
226
+
Linux uses pinned values (`Pin<P>`, values that can't move around in memory), raw pointers and `MaybeUninit` all over the place in addition to many custom fields that would greatly benefit from field projections.
227
227
228
228
[Benno Lossin](https://github.com/BennoLossin) who owns the [Field Projection goal][field-projections] prepared a [design](https://hackmd.io/@rust-lang-team/S1I1aEc_lx) to move this forward as a lang experiment. This was approved, we now have a [Field Projection tracking issue](https://github.com/rust-lang/rust/issues/145383) as well as an [initial implementation](https://github.com/BennoLossin/rust/tree/field-projections).
0 commit comments