Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local with required config as a const generic parameter #2463

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/bevy_app/src/ci_testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct CiTestingConfig {
}

fn ci_testing_exit_after(
mut current_frame: bevy_ecs::prelude::Local<u32>,
mut current_frame: bevy_ecs::prelude::Local<u32, true>,
ci_testing_config: bevy_ecs::prelude::Res<CiTestingConfig>,
mut app_exit_events: crate::EventWriter<AppExit>,
) {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core/src/time/fixed_timestep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl FixedTimestep {
}

fn prepare_system(
mut state: Local<State>,
mut state: Local<State, true>,
time: Res<Time>,
mut fixed_timesteps: ResMut<FixedTimesteps>,
) -> ShouldRun {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ fn map_instance_event<T>(event_instance: &EventInstance<T>) -> &T {
/// Reads events of type `T` in order and tracks which events have already been read.
#[derive(SystemParam)]
pub struct EventReader<'a, T: Component> {
last_event_count: Local<'a, (usize, PhantomData<T>)>,
last_event_count: Local<'a, (usize, PhantomData<T>), true>,
events: Res<'a, Events<T>>,
}

Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/schedule/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ mod tests {
}};
}

fn every_other_time(mut has_ran: Local<bool>) -> ShouldRun {
fn every_other_time(mut has_ran: Local<bool, true>) -> ShouldRun {
*has_ran = !*has_ran;
if *has_ran {
ShouldRun::Yes
Expand Down Expand Up @@ -1456,7 +1456,7 @@ mod tests {

// Piping criteria.
world.get_resource_mut::<Vec<usize>>().unwrap().clear();
fn eot_piped(input: In<ShouldRun>, has_ran: Local<bool>) -> ShouldRun {
fn eot_piped(input: In<ShouldRun>, has_ran: Local<bool, true>) -> ShouldRun {
if let ShouldRun::Yes | ShouldRun::YesAndCheckAgain = input.0 {
every_other_time(has_ran)
} else {
Expand Down
24 changes: 12 additions & 12 deletions crates/bevy_ecs/src/schedule/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ where
T: Component + Debug + Clone + Eq + Hash,
{
pub fn on_update(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, pred: Local<Option<T>>| {
(|state: Res<State<T>>, pred: Local<Option<T>, true>| {
state.stack.last().unwrap() == pred.as_ref().unwrap() && state.transition.is_none()
})
.system()
Expand All @@ -105,9 +105,9 @@ where
}

pub fn on_inactive_update(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, mut is_inactive: Local<bool>, pred: Local<Option<T>>| match &state
.transition
{
(|state: Res<State<T>>,
mut is_inactive: Local<bool, true>,
pred: Local<Option<T>, true>| match &state.transition {
Some(StateTransition::Pausing(ref relevant, _))
| Some(StateTransition::Resuming(_, ref relevant)) => {
if relevant == pred.as_ref().unwrap() {
Expand All @@ -126,9 +126,9 @@ where
}

pub fn on_in_stack_update(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, mut is_in_stack: Local<bool>, pred: Local<Option<T>>| match &state
.transition
{
(|state: Res<State<T>>,
mut is_in_stack: Local<bool, true>,
pred: Local<Option<T>, true>| match &state.transition {
Some(StateTransition::Entering(ref relevant, _))
| Some(StateTransition::ExitingToResume(_, ref relevant)) => {
if relevant == pred.as_ref().unwrap() {
Expand Down Expand Up @@ -159,7 +159,7 @@ where
}

pub fn on_enter(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, pred: Local<Option<T>>| {
(|state: Res<State<T>>, pred: Local<Option<T>, true>| {
state
.transition
.as_ref()
Expand All @@ -179,7 +179,7 @@ where
}

pub fn on_exit(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, pred: Local<Option<T>>| {
(|state: Res<State<T>>, pred: Local<Option<T>, true>| {
state
.transition
.as_ref()
Expand All @@ -197,7 +197,7 @@ where
}

pub fn on_pause(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, pred: Local<Option<T>>| {
(|state: Res<State<T>>, pred: Local<Option<T>, true>| {
state
.transition
.as_ref()
Expand All @@ -214,7 +214,7 @@ where
}

pub fn on_resume(s: T) -> RunCriteriaDescriptor {
(|state: Res<State<T>>, pred: Local<Option<T>>| {
(|state: Res<State<T>>, pred: Local<Option<T>, true>| {
state
.transition
.as_ref()
Expand Down Expand Up @@ -410,7 +410,7 @@ fn should_run_adapter<T: Component + Clone + Eq>(

fn state_cleaner<T: Component + Clone + Eq>(
mut state: ResMut<State<T>>,
mut prep_exit: Local<bool>,
mut prep_exit: Local<bool, true>,
) -> ShouldRun {
if *prep_exit {
*prep_exit = false;
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/system/function_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ impl<In, Out, Param: SystemParam, Marker, F> FunctionSystem<In, Out, Param, Mark
/// ```
/// # use bevy_ecs::prelude::*;
/// # let world = &mut World::default();
/// fn local_is_42(local: Local<usize>) {
/// fn local_is_42(local: Local<usize, false>) {
/// assert_eq!(*local, 42);
/// }
/// let mut system = local_is_42.system().config(|config| config.0 = Some(42));
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_ecs/src/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ mod tests {

#[test]
fn nonconflicting_system_resources() {
fn sys(_: Local<BufferRes>, _: ResMut<BufferRes>, _: Local<A>, _: ResMut<A>) {}
fn sys(_: Local<BufferRes, true>, _: ResMut<BufferRes>, _: Local<A, true>, _: ResMut<A>) {}
test_for_conflicting_resources(sys.system())
}

Expand All @@ -316,7 +316,7 @@ mod tests {
}
}

fn sys(local: Local<Foo>, mut modified: ResMut<bool>) {
fn sys(local: Local<Foo, true>, mut modified: ResMut<bool>) {
assert_eq!(local.value, 2);
*modified = true;
}
Expand Down Expand Up @@ -360,7 +360,7 @@ mod tests {
fn configure_system_local() {
let mut world = World::default();
world.insert_resource(false);
fn sys(local: Local<usize>, mut modified: ResMut<bool>) {
fn sys(local: Local<usize, true>, mut modified: ResMut<bool>) {
assert_eq!(*local, 42);
*modified = true;
}
Expand Down
55 changes: 42 additions & 13 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,10 +516,10 @@ impl<'a> SystemParamFetch<'a> for CommandQueue {
/// ```
/// # use bevy_ecs::prelude::*;
/// # let world = &mut World::default();
/// fn write_to_local(mut local: Local<usize>) {
/// fn write_to_local(mut local: Local<usize, true>) {
/// *local = 42;
/// }
/// fn read_from_local(local: Local<usize>) -> usize {
/// fn read_from_local(local: Local<usize, true>) -> usize {
/// *local
/// }
/// let mut write_system = write_to_local.system();
Expand All @@ -532,12 +532,12 @@ impl<'a> SystemParamFetch<'a> for CommandQueue {
/// // Note how the read local is still 0 due to the locals not being shared.
/// assert_eq!(read_system.run((), world), 0);
/// ```
pub struct Local<'a, T: Component>(&'a mut T);
pub struct Local<'a, T: Component, const DEFAULT: bool>(&'a mut T);

// SAFE: Local only accesses internal state
unsafe impl<T: Component> ReadOnlySystemParamFetch for LocalState<T> {}
unsafe impl<T: Component, const DEFAULT: bool> ReadOnlySystemParamFetch for LocalState<T, DEFAULT> {}

impl<'a, T: Component> Debug for Local<'a, T>
impl<'a, T: Component, const DEFAULT: bool> Debug for Local<'a, T, DEFAULT>
where
T: Debug,
{
Expand All @@ -546,7 +546,7 @@ where
}
}

impl<'a, T: Component> Deref for Local<'a, T> {
impl<'a, T: Component, const DEFAULT: bool> Deref for Local<'a, T, DEFAULT> {
type Target = T;

#[inline]
Expand All @@ -555,22 +555,26 @@ impl<'a, T: Component> Deref for Local<'a, T> {
}
}

impl<'a, T: Component> DerefMut for Local<'a, T> {
impl<'a, T: Component, const DEFAULT: bool> DerefMut for Local<'a, T, DEFAULT> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}

/// The [`SystemParamState`] of [`Local`].
pub struct LocalState<T: Component>(T);
pub struct LocalState<T: Component, const DEFAULT: bool>(T);

impl<'a, T: Component + FromWorld> SystemParam for Local<'a, T> {
type Fetch = LocalState<T>;
impl<'a, T: Component + FromWorld> SystemParam for Local<'a, T, true> {
type Fetch = LocalState<T, true>;
}

impl<'a, T: Component> SystemParam for Local<'a, T, false> {
type Fetch = LocalState<T, false>;
}

// SAFE: only local state is accessed
unsafe impl<T: Component + FromWorld> SystemParamState for LocalState<T> {
unsafe impl<T: Component + FromWorld> SystemParamState for LocalState<T, true> {
type Config = Option<T>;

fn init(world: &mut World, _system_meta: &mut SystemMeta, config: Self::Config) -> Self {
Expand All @@ -581,9 +585,34 @@ unsafe impl<T: Component + FromWorld> SystemParamState for LocalState<T> {
None
}
}
unsafe impl<T: Component> SystemParamState for LocalState<T, false> {
type Config = Option<T>;

fn init(_world: &mut World, _system_meta: &mut SystemMeta, config: Self::Config) -> Self {
Self(config.expect("Local must be initialized using config!"))
}

fn default_config() -> Option<T> {
None
}
}

impl<'a, T: Component + FromWorld> SystemParamFetch<'a> for LocalState<T, true> {
type Item = Local<'a, T, true>;

#[inline]
unsafe fn get_param(
state: &'a mut Self,
_system_meta: &SystemMeta,
_world: &'a World,
_change_tick: u32,
) -> Self::Item {
Local(&mut state.0)
}
}

impl<'a, T: Component + FromWorld> SystemParamFetch<'a> for LocalState<T> {
type Item = Local<'a, T>;
impl<'a, T: Component> SystemParamFetch<'a> for LocalState<T, false> {
type Item = Local<'a, T, false>;

#[inline]
unsafe fn get_param(
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render_graph/lights_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub struct LightsNodeSystemState {
}

pub fn lights_node_system(
mut state: Local<LightsNodeSystemState>,
mut state: Local<LightsNodeSystemState, true>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
ambient_light_resource: Res<AmbientLight>,
// TODO: this write on RenderResourceBindings will prevent this system from running in parallel
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_render/src/mesh/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ pub struct MeshResourceProviderState {

#[allow(clippy::type_complexity)]
pub fn mesh_resource_provider_system(
mut state: Local<MeshResourceProviderState>,
mut state: Local<MeshResourceProviderState, true>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
meshes: Res<Assets<Mesh>>,
mut mesh_events: EventReader<AssetEvent<Mesh>>,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_render/src/render_graph/nodes/camera_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const MATRIX_SIZE: usize = std::mem::size_of::<[[f32; 4]; 4]>();
const VEC4_SIZE: usize = std::mem::size_of::<[f32; 4]>();

pub fn camera_node_system(
mut state: Local<CameraNodeState>,
mut state: Local<CameraNodeState, true>,
mut active_cameras: ResMut<ActiveCameras>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
mut query: Query<(&Camera, &GlobalTransform)>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ impl<I, T: RenderResources> Default for RenderResourcesNodeState<I, T> {

#[allow(clippy::type_complexity)]
fn render_resources_node_system<T: RenderResources>(
mut state: Local<RenderResourcesNodeState<Entity, T>>,
mut entities_waiting_for_textures: Local<Vec<Entity>>,
mut state: Local<RenderResourcesNodeState<Entity, T>, true>,
mut entities_waiting_for_textures: Local<Vec<Entity>, true>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
removed: RemovedComponents<T>,
mut queries: QuerySet<(
Expand Down Expand Up @@ -613,8 +613,8 @@ impl<T: Asset> Default for AssetRenderNodeState<T> {

#[allow(clippy::too_many_arguments, clippy::type_complexity)]
fn asset_render_resources_node_system<T: RenderResources + Asset>(
mut state: Local<RenderResourcesNodeState<HandleId, T>>,
mut asset_state: Local<AssetRenderNodeState<T>>,
mut state: Local<RenderResourcesNodeState<HandleId, T>, true>,
mut asset_state: Local<AssetRenderNodeState<T>, true>,
assets: Res<Assets<T>>,
mut asset_events: EventReader<AssetEvent<T>>,
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_sprite/src/color_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ impl From<Handle<Texture>> for ColorMaterial {
// TODO: should be removed when pipelined rendering is done
#[allow(clippy::type_complexity)]
pub(crate) fn material_texture_detection_system(
mut texture_to_material: Local<HashMap<Handle<Texture>, HashSet<Handle<ColorMaterial>>>>,
mut material_to_texture: Local<HashMap<Handle<ColorMaterial>, Handle<Texture>>>,
mut texture_to_material: Local<HashMap<Handle<Texture>, HashSet<Handle<ColorMaterial>>>, true>,
mut material_to_texture: Local<HashMap<Handle<ColorMaterial>, Handle<Texture>>, true>,
materials: Res<Assets<ColorMaterial>>,
mut texture_events: EventReader<AssetEvent<Texture>>,
(mut material_events_reader, mut material_events): (
Local<ManualEventReader<AssetEvent<ColorMaterial>>>,
Local<ManualEventReader<AssetEvent<ColorMaterial>>, true>,
ResMut<Events<AssetEvent<ColorMaterial>>>,
),
) {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_text/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub struct QueuedText2d {
/// Updates the TextGlyphs with the new computed glyphs from the layout
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub fn text2d_system(
mut queued_text: Local<QueuedText2d>,
mut queued_text: Local<QueuedText2d, true>,
mut textures: ResMut<Assets<Texture>>,
fonts: Res<Assets<Font>>,
windows: Res<Windows>,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub struct State {

#[allow(clippy::type_complexity)]
pub fn ui_focus_system(
mut state: Local<State>,
mut state: Local<State, true>,
windows: Res<Windows>,
mouse_button_input: Res<Input<MouseButton>>,
touches_input: Res<Touches>,
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ui/src/widget/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ pub fn text_constraint(min_size: Val, size: Val, max_size: Val, scale_factor: f6
/// new computed glyphs from the layout
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub fn text_system(
mut queued_text: Local<QueuedText>,
mut last_scale_factor: Local<f64>,
mut queued_text: Local<QueuedText, true>,
mut last_scale_factor: Local<f64, true>,
mut textures: ResMut<Assets<Texture>>,
fonts: Res<Assets<Font>>,
windows: Res<Windows>,
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/update_gltf_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ fn scene_update(
mut commands: Commands,
scene_spawner: Res<SceneSpawner>,
scene_instance: Res<SceneInstance>,
mut done: Local<bool>,
mut done: Local<bool, true>,
) {
if !*done {
if let Some(instance_id) = scene_instance.0 {
Expand Down
2 changes: 1 addition & 1 deletion examples/app/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn hello_world_system() {
println!("hello world");
}

fn counter(mut state: Local<CounterState>) {
fn counter(mut state: Local<CounterState, true>) {
if state.count % 60 == 0 {
println!("{}", state.count);
}
Expand Down
2 changes: 1 addition & 1 deletion examples/ecs/ecs_guide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ struct State {

// NOTE: this doesn't do anything relevant to our game, it is just here for illustrative purposes
#[allow(dead_code)]
fn local_state_system(mut state: Local<State>, query: Query<(&Player, &Score)>) {
fn local_state_system(mut state: Local<State, true>, query: Query<(&Player, &Score)>) {
for (player, score) in query.iter() {
println!("processed: {} {}", player.name, score.value);
}
Expand Down
Loading