Skip to content

Commit c0c5fae

Browse files
committed
fix a soundness issue
1 parent 2d2e05b commit c0c5fae

File tree

1 file changed

+17
-44
lines changed

1 file changed

+17
-44
lines changed

crates/bevy_app/src/sub_schedule.rs

+17-44
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,14 @@ use crate::App;
1313

1414
/// Methods for converting a schedule into a [sub-Schedule](SubSchedule) descriptor.
1515
pub trait IntoSubSchedule: Sized {
16-
/// The wrapped schedule type.
17-
type Sched: Stage;
1816
/// The type that controls the behaviour of the exclusive system
1917
/// which runs [`SubSchedule`]s of this type.
20-
type Runner: FnMut(&mut Self::Sched, &mut World) + Send + Sync + 'static;
18+
type Runner: FnMut(&mut dyn Stage, &mut World) + Send + Sync + 'static;
2119

2220
/// Applies the specified label to the current schedule.
2321
/// This means it will be accessible in the [`SubSchedules`] resource after
2422
/// being added to the [`App`].
25-
fn label(self, label: impl ScheduleLabel) -> SubSchedule<Self::Sched, Self::Runner> {
23+
fn label(self, label: impl ScheduleLabel) -> SubSchedule<Self::Runner> {
2624
let mut sub = Self::into_sched(self);
2725
sub.label = Some(label.as_label());
2826
sub
@@ -31,9 +29,9 @@ pub trait IntoSubSchedule: Sized {
3129
/// an exclusive system within the stage `stage`.
3230
///
3331
/// Overwrites any previously set runner or stage.
34-
fn with_runner<F>(self, stage: impl StageLabel, f: F) -> SubSchedule<Self::Sched, F>
32+
fn with_runner<F>(self, stage: impl StageLabel, f: F) -> SubSchedule<F>
3533
where
36-
F: FnMut(&mut Self::Sched, &mut World) + Send + Sync + 'static,
34+
F: FnMut(&mut dyn Stage, &mut World) + Send + Sync + 'static,
3735
{
3836
let SubSchedule {
3937
schedule, label, ..
@@ -46,39 +44,37 @@ pub trait IntoSubSchedule: Sized {
4644
}
4745

4846
/// Performs the conversion. You usually do not need to call this directly.
49-
fn into_sched(_: Self) -> SubSchedule<Self::Sched, Self::Runner>;
47+
fn into_sched(_: Self) -> SubSchedule<Self::Runner>;
5048
}
5149

5250
impl<S: Stage> IntoSubSchedule for S {
53-
type Sched = Self;
54-
type Runner = fn(&mut Self, &mut World);
55-
fn into_sched(schedule: Self) -> SubSchedule<Self, Self::Runner> {
51+
type Runner = fn(&mut dyn Stage, &mut World);
52+
fn into_sched(schedule: Self) -> SubSchedule<Self::Runner> {
5653
SubSchedule {
57-
schedule,
54+
schedule: Box::new(schedule),
5855
label: None,
5956
runner: None,
6057
}
6158
}
6259
}
6360

64-
impl<S: Stage, R> IntoSubSchedule for SubSchedule<S, R>
61+
impl<R> IntoSubSchedule for SubSchedule<R>
6562
where
66-
R: FnMut(&mut S, &mut World) + Send + Sync + 'static,
63+
R: FnMut(&mut dyn Stage, &mut World) + Send + Sync + 'static,
6764
{
68-
type Sched = S;
6965
type Runner = R;
7066
#[inline]
71-
fn into_sched(sched: Self) -> SubSchedule<S, R> {
67+
fn into_sched(sched: Self) -> SubSchedule<R> {
7268
sched
7369
}
7470
}
7571

7672
/// A schedule that may run independently of the main app schedule.
77-
pub struct SubSchedule<S: Stage, F>
73+
pub struct SubSchedule<F>
7874
where
79-
F: FnMut(&mut S, &mut World) + Send + Sync + 'static,
75+
F: FnMut(&mut dyn Stage, &mut World) + Send + Sync + 'static,
8076
{
81-
schedule: S,
77+
schedule: Box<dyn Stage>,
8278
label: Option<ScheduleLabelId>,
8379
runner: Option<(StageLabelId, F)>,
8480
}
@@ -208,7 +204,7 @@ impl SubSchedules {
208204
}
209205

210206
#[track_caller]
211-
pub(crate) fn add_to_app<S: Stage>(app: &mut App, schedule: impl IntoSubSchedule<Sched = S>) {
207+
pub(crate) fn add_to_app(app: &mut App, schedule: impl IntoSubSchedule) {
212208
let SubSchedule {
213209
mut schedule,
214210
label,
@@ -218,35 +214,12 @@ pub(crate) fn add_to_app<S: Stage>(app: &mut App, schedule: impl IntoSubSchedule
218214
// If it has a label, insert it to the public resource.
219215
if let Some(label) = label {
220216
let mut res: Mut<SubSchedules> = app.world.get_resource_or_insert_with(Default::default);
221-
res.insert(label, Box::new(schedule)).unwrap();
217+
res.insert(label, schedule).unwrap();
222218

223219
if let Some((stage, mut runner)) = runner {
224220
// Driver which extracts the schedule from the world and runs it.
225221
let driver = move |w: &mut World| {
226222
SubSchedules::extract_scope(w, label, |w, sched| {
227-
let sched = if let Some(s) = sched.downcast_mut::<S>() {
228-
s
229-
} else {
230-
#[cfg(debug_assertions)]
231-
unreachable!(
232-
r#"
233-
The sub-schedule '{label:?}' changed types after being inserted:
234-
it should be of type `{expect}`, but it's really of type `{actual}`.
235-
This should be impossible.
236-
If you run into this error, please file an issue at https://github.com/bevyengine/bevy/issues/new/choose"#,
237-
expect = std::any::type_name::<S>(),
238-
actual = AnyTypeName::name(sched),
239-
);
240-
// SAFETY: Due to the invariant on `SubSchedules`, we can be sure that
241-
// `sched` is the same instance that we inserted.
242-
// Thus, we can rely on its type matching `S`.
243-
//
244-
// FIXME: this is unsound
245-
#[cfg(not(debug_assertions))]
246-
unsafe {
247-
std::hint::unreachable_unchecked()
248-
}
249-
};
250223
runner(sched, w);
251224
})
252225
.unwrap();
@@ -257,7 +230,7 @@ pub(crate) fn add_to_app<S: Stage>(app: &mut App, schedule: impl IntoSubSchedule
257230
// If there's no label, then the schedule isn't visible publicly.
258231
// We can just store it locally
259232
let driver = move |w: &mut World| {
260-
runner(&mut schedule, w);
233+
runner(schedule.as_mut(), w);
261234
};
262235
app.add_system_to_stage(stage, driver.exclusive_system());
263236
} else {

0 commit comments

Comments
 (0)