From 3d280ec37b9558db65785e10a774f5bf721b8c63 Mon Sep 17 00:00:00 2001 From: Zachary Harrold Date: Mon, 30 Dec 2024 06:12:29 +1100 Subject: [PATCH 01/11] Add `no_std` support to `bevy_hierarchy` (#16998) # Objective - Contributes to #15460 ## Solution - Added the following features: - `std` (default) ## Testing - CI ## Notes - There was a minor issue with `bevy_reflect`'s `smallvec` feature noticed in this PR which I have also resolved here. I can split this out if desired, but I've left it here for now as it's a very small change and I don't consider this PR itself to be very controversial. --- crates/bevy_hierarchy/Cargo.toml | 51 +++++++++++++++---- crates/bevy_hierarchy/src/hierarchy.rs | 26 +++++----- crates/bevy_hierarchy/src/lib.rs | 8 +-- .../src/valid_parent_check_plugin.rs | 4 +- crates/bevy_reflect/src/impls/smallvec.rs | 2 +- tools/ci/src/commands/compile_check_no_std.rs | 8 +++ 6 files changed, 70 insertions(+), 29 deletions(-) diff --git a/crates/bevy_hierarchy/Cargo.toml b/crates/bevy_hierarchy/Cargo.toml index 093f5f7f88c3a..2e536798a3a87 100644 --- a/crates/bevy_hierarchy/Cargo.toml +++ b/crates/bevy_hierarchy/Cargo.toml @@ -9,23 +9,54 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -default = ["bevy_app"] -trace = [] -bevy_app = ["reflect", "dep:bevy_app"] -reflect = ["bevy_ecs/bevy_reflect", "bevy_reflect"] +default = ["std", "bevy_app", "reflect"] + +# Functionality + +## Adds integration with the `bevy_app` plugin API. +bevy_app = ["dep:bevy_app"] + +## Adds runtime reflection support using `bevy_reflect`. +reflect = ["bevy_ecs/bevy_reflect", "bevy_reflect", "bevy_app?/bevy_reflect"] + +# Debugging Features + +## Enables `tracing` integration, allowing spans and other metrics to be reported +## through that framework. +trace = ["dep:tracing"] + +# Platform Compatibility + +## Allows access to the `std` crate. Enabling this feature will prevent compilation +## on `no_std` targets, but provides access to certain additional features on +## supported platforms. +std = [ + "bevy_app?/std", + "bevy_ecs/std", + "bevy_reflect/std", + "bevy_utils/std", + "disqualified/alloc", +] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true } +bevy_app = { path = "../bevy_app", version = "0.15.0-dev", default-features = false, optional = true } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [ - "bevy", "smallvec", -], optional = true } -bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" } -disqualified = "1.0" +], default-features = false, optional = true } +bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev", default-features = false, features = [ + "alloc", +] } +disqualified = { version = "1.0", default-features = false } -smallvec = { version = "1.11", features = ["union", "const_generics"] } +# other +smallvec = { version = "1.11", default-features = false, features = [ + "union", + "const_generics", +] } +tracing = { version = "0.1", default-features = false, optional = true } +log = { version = "0.4", default-features = false } [lints] workspace = true diff --git a/crates/bevy_hierarchy/src/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy.rs index 65d6aa3df8960..7b384d25e621e 100644 --- a/crates/bevy_hierarchy/src/hierarchy.rs +++ b/crates/bevy_hierarchy/src/hierarchy.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ system::EntityCommands, world::{Command, DeferredWorld, EntityWorldMut, World}, }; -use bevy_utils::tracing::debug; +use log::debug; /// Despawns the given entity and all its children recursively #[derive(Debug)] @@ -69,11 +69,11 @@ fn despawn_children_recursive(world: &mut World, entity: Entity, warn: bool) { impl Command for DespawnRecursive { fn apply(self, world: &mut World) { #[cfg(feature = "trace")] - let _span = bevy_utils::tracing::info_span!( + let _span = tracing::info_span!( "command", name = "DespawnRecursive", - entity = bevy_utils::tracing::field::debug(self.entity), - warn = bevy_utils::tracing::field::debug(self.warn) + entity = tracing::field::debug(self.entity), + warn = tracing::field::debug(self.warn) ) .entered(); despawn_with_children_recursive(world, self.entity, self.warn); @@ -83,11 +83,11 @@ impl Command for DespawnRecursive { impl Command for DespawnChildrenRecursive { fn apply(self, world: &mut World) { #[cfg(feature = "trace")] - let _span = bevy_utils::tracing::info_span!( + let _span = tracing::info_span!( "command", name = "DespawnChildrenRecursive", - entity = bevy_utils::tracing::field::debug(self.entity), - warn = bevy_utils::tracing::field::debug(self.warn) + entity = tracing::field::debug(self.entity), + warn = tracing::field::debug(self.warn) ) .entered(); @@ -150,10 +150,10 @@ fn despawn_recursive_inner(world: EntityWorldMut, warn: bool) { let entity = world.id(); #[cfg(feature = "trace")] - let _span = bevy_utils::tracing::info_span!( + let _span = tracing::info_span!( "despawn_recursive", - entity = bevy_utils::tracing::field::debug(entity), - warn = bevy_utils::tracing::field::debug(warn) + entity = tracing::field::debug(entity), + warn = tracing::field::debug(warn) ) .entered(); @@ -167,10 +167,10 @@ fn despawn_descendants_inner<'v, 'w>( let entity = world.id(); #[cfg(feature = "trace")] - let _span = bevy_utils::tracing::info_span!( + let _span = tracing::info_span!( "despawn_descendants", - entity = bevy_utils::tracing::field::debug(entity), - warn = bevy_utils::tracing::field::debug(warn) + entity = tracing::field::debug(entity), + warn = tracing::field::debug(warn) ) .entered(); diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index ced37bd154f64..ec42846b14b23 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -4,6 +4,7 @@ html_logo_url = "https://bevyengine.org/assets/icon.png", html_favicon_url = "https://bevyengine.org/assets/icon.png" )] +#![cfg_attr(not(feature = "std"), no_std)] //! Parent-child relationships for Bevy entities. //! @@ -98,8 +99,9 @@ pub struct HierarchyPlugin; #[cfg(feature = "bevy_app")] impl Plugin for HierarchyPlugin { fn build(&self, app: &mut App) { - app.register_type::() - .register_type::() - .add_event::(); + #[cfg(feature = "reflect")] + app.register_type::().register_type::(); + + app.add_event::(); } } diff --git a/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs b/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs index a05ec586cfdfd..c17059c3f3b83 100644 --- a/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs +++ b/crates/bevy_hierarchy/src/valid_parent_check_plugin.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use bevy_ecs::prelude::*; #[cfg(feature = "bevy_app")] -use {crate::Parent, bevy_utils::HashSet, disqualified::ShortName}; +use {crate::Parent, alloc::format, bevy_utils::HashSet, disqualified::ShortName}; /// When enabled, runs [`check_hierarchy_component_has_valid_parent`]. /// @@ -63,7 +63,7 @@ pub fn check_hierarchy_component_has_valid_parent( let parent = parent.get(); if !component_query.contains(parent) && !already_diagnosed.contains(&entity) { already_diagnosed.insert(entity); - bevy_utils::tracing::warn!( + log::warn!( "warning[B0004]: {name} with the {ty_name} component has a parent without {ty_name}.\n\ This will cause inconsistent behaviors! See: https://bevyengine.org/learn/errors/b0004", ty_name = ShortName::of::(), diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 793ca2001ccc1..f0958c65ea60e 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -4,7 +4,7 @@ use core::any::Any; use smallvec::{Array as SmallArray, SmallVec}; #[cfg(not(feature = "std"))] -use alloc::{format, vec}; +use alloc::{format, vec, vec::Vec}; use crate::{ self as bevy_reflect, utility::GenericTypeInfoCell, ApplyError, FromReflect, FromType, diff --git a/tools/ci/src/commands/compile_check_no_std.rs b/tools/ci/src/commands/compile_check_no_std.rs index 7ca5d6b2b5905..946bed361af6c 100644 --- a/tools/ci/src/commands/compile_check_no_std.rs +++ b/tools/ci/src/commands/compile_check_no_std.rs @@ -110,6 +110,14 @@ impl Prepare for CompileCheckNoStdCommand { "Please fix compiler errors in output above for bevy_app no_std compatibility.", )); + commands.push(PreparedCommand::new::( + cmd!( + sh, + "cargo check -p bevy_hierarchy --no-default-features --features bevy_app,reflect --target {target}" + ), + "Please fix compiler errors in output above for bevy_hierarchy no_std compatibility.", + )); + commands } } From 31367108f73469bcb7d84452f7191c353a08805d Mon Sep 17 00:00:00 2001 From: to-bak Date: Sun, 29 Dec 2024 20:20:51 +0100 Subject: [PATCH 02/11] Update linux dependency documentation for NixOS (and nix) (#16881) # Objective - Updates the linux-dependencies docs to 1) fix problems with nix `alsa-lib`, and 2) include additional documentation to run bevy with nix on non NixOS systems. (nix is a package manager that can be run outside of NixOS). ## Solution 1. the nix `alsa-lib` package doesn't include `alsa-plugins`, which bevy depends on. Instead, use the `alsa-lib-with-plugins` package, which wraps `alsa-plugins` into `alsa-lib`. For more information see: https://github.com/NixOS/nixpkgs/pull/277180 2. using nix on non NixOS systems, software like `nixGL` is required to correctly link graphics drivers. ## Testing - Tested on ubuntu 22.04 with nix. --- docs/linux_dependencies.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/linux_dependencies.md b/docs/linux_dependencies.md index 521a198157e48..cc77ae8eb98d0 100644 --- a/docs/linux_dependencies.md +++ b/docs/linux_dependencies.md @@ -122,7 +122,7 @@ mkShell rec { pkg-config ]; buildInputs = [ - udev alsa-lib vulkan-loader + udev alsa-lib-with-plugins vulkan-loader xorg.libX11 xorg.libXcursor xorg.libXi xorg.libXrandr # To use the x11 feature libxkbcommon wayland # To use the wayland feature ]; @@ -134,6 +134,14 @@ And enter it by just running `nix-shell`. You should be able compile Bevy programs using `cargo run` within this nix-shell. You can do this in one line with `nix-shell --run "cargo run"`. +If running nix on a non NixOS system (such as ubuntu, arch etc.), [NixGL](https://github.com/nix-community/nixGL) is additionally required, +to link graphics drivers into the context of software installed by nix: + +1. Install an system specific nixGL wrapper ([docs](https://github.com/nix-community/nixGL)). + * If you're running a nvidia GPU choose `nixVulkanNvidia`. + * Otherwise, choose another wrapper appropriate for your system. +2. Run `nixVulkanNvidia-xxx.xxx.xx cargo run` to compile a bevy program, where `xxx-xxx-xx` denotes the graphics driver version `nixVulkanNvidia` was compiled with. + This is also possible with [Nix flakes](https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html). Instead of creating `shell.nix`, you just need to add the derivation (`mkShell`) to your `devShells` in `flake.nix`. Run `nix develop` to enter the shell and From 97909df6c07b65c33ad8238e9834849a09ada050 Mon Sep 17 00:00:00 2001 From: Matty Weatherley Date: Sun, 29 Dec 2024 14:26:49 -0500 Subject: [PATCH 03/11] Refactor non-core Curve methods into extension traits (#16930) # Objective The way `Curve` presently achieves dyn-compatibility involves shoving `Self: Sized` bounds on a bunch of methods to forbid them from appearing in vtables. (This is called *explicit non-dispatchability*.) The `Curve` trait probably also just has way too many methods on its own. In the past, using extension traits instead to achieve similar functionality has been discussed. The upshot is that this would allow the "core" of the curve trait, on which all the automatic methods rely, to live in a very simple dyn-compatible trait, while other functionality is implemented by extensions. For instance, `dyn Curve` cannot use the `Sized` methods, but `Box>` is `Sized`, hence would automatically implement the extension trait, containing the methods which are currently non-dispatchable. Other motivations for this include modularity and code organization: the `Curve` trait itself has grown quite large with the addition of numerous adaptors, and refactoring it to demonstrate the separation of functionality that is already present makes a lot of sense. Furthermore, resampling behavior in particular is dependent on special traits that may be mimicked or analogized in user-space, and creating extension traits to achieve similar behavior in user-space is something we ought to encourage by example. ## Solution `Curve` now contains only `domain` and the `sample` methods. `CurveExt` has been created, and it contains all adaptors, along with the other sampling convenience methods (`samples`, `sample_iter`, etc.). It is implemented for all `C` where `C: Curve + Sized`. `CurveResampleExt` has been created, and it contains all resampling methods. It is implemented for all `C` where `C: Curve + ?Sized`. ## Testing It compiles and `cargo doc` succeeds. --- ## Future work - Consider writing extension traits for resampling curves in related domains (e.g. resampling for `Curve` where `T: Animatable` into an `AnimatableKeyframeCurve`). - `CurveExt` might be further broken down to separate the adaptor and sampling methods. --- ## Migration Guide `Curve` has been refactored so that much of its functionality is now in extension traits. Adaptors such as `map`, `reparametrize`, `reverse`, and so on now require importing `CurveExt`, while the resampling methods `resample_*` require importing `CurveResampleExt`. Both of these new traits are exported through `bevy::math::curve` and through `bevy::math::prelude`. --- crates/bevy_color/src/color_gradient.rs | 1 + crates/bevy_gizmos/src/curves.rs | 5 +- crates/bevy_math/src/curve/adaptors.rs | 27 +- crates/bevy_math/src/curve/cores.rs | 4 +- .../src/curve/derivatives/adaptor_impls.rs | 2 +- crates/bevy_math/src/curve/derivatives/mod.rs | 2 +- crates/bevy_math/src/curve/easing.rs | 4 +- crates/bevy_math/src/curve/mod.rs | 295 +++++++++--------- crates/bevy_math/src/curve/sample_curves.rs | 8 +- 9 files changed, 187 insertions(+), 161 deletions(-) diff --git a/crates/bevy_color/src/color_gradient.rs b/crates/bevy_color/src/color_gradient.rs index 759b33bf93e77..b087205bb6b49 100644 --- a/crates/bevy_color/src/color_gradient.rs +++ b/crates/bevy_color/src/color_gradient.rs @@ -76,6 +76,7 @@ where mod tests { use super::*; use crate::{palettes::basic, Srgba}; + use bevy_math::curve::{Curve, CurveExt}; #[test] fn test_color_curve() { diff --git a/crates/bevy_gizmos/src/curves.rs b/crates/bevy_gizmos/src/curves.rs index 522bf8ebd5246..2d7a350ca29dc 100644 --- a/crates/bevy_gizmos/src/curves.rs +++ b/crates/bevy_gizmos/src/curves.rs @@ -4,7 +4,10 @@ //! [`GizmoBuffer::curve_3d`] and assorted support items. use bevy_color::Color; -use bevy_math::{curve::Curve, Vec2, Vec3}; +use bevy_math::{ + curve::{Curve, CurveExt}, + Vec2, Vec3, +}; use crate::{gizmos::GizmoBuffer, prelude::GizmoConfigGroup}; diff --git a/crates/bevy_math/src/curve/adaptors.rs b/crates/bevy_math/src/curve/adaptors.rs index 20e0bcd29c937..8b27dc538720f 100644 --- a/crates/bevy_math/src/curve/adaptors.rs +++ b/crates/bevy_math/src/curve/adaptors.rs @@ -18,6 +18,9 @@ mod paths { pub(super) const THIS_CRATE: &str = "bevy_math"; } +#[expect(unused, reason = "imported just for doc links")] +use super::CurveExt; + // NOTE ON REFLECTION: // // Function members of structs pose an obstacle for reflection, because they don't implement @@ -173,7 +176,7 @@ where } /// A curve whose samples are defined by mapping samples from another curve through a -/// given function. Curves of this type are produced by [`Curve::map`]. +/// given function. Curves of this type are produced by [`CurveExt::map`]. #[derive(Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -269,7 +272,7 @@ where } /// A curve whose sample space is mapped onto that of some base curve's before sampling. -/// Curves of this type are produced by [`Curve::reparametrize`]. +/// Curves of this type are produced by [`CurveExt::reparametrize`]. #[derive(Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -364,7 +367,7 @@ where } /// A curve that has had its domain changed by a linear reparameterization (stretching and scaling). -/// Curves of this type are produced by [`Curve::reparametrize_linear`]. +/// Curves of this type are produced by [`CurveExt::reparametrize_linear`]. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -399,7 +402,7 @@ where } /// A curve that has been reparametrized by another curve, using that curve to transform the -/// sample times before sampling. Curves of this type are produced by [`Curve::reparametrize_by_curve`]. +/// sample times before sampling. Curves of this type are produced by [`CurveExt::reparametrize_by_curve`]. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -432,7 +435,7 @@ where } /// A curve that is the graph of another curve over its parameter space. Curves of this type are -/// produced by [`Curve::graph`]. +/// produced by [`CurveExt::graph`]. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -462,7 +465,7 @@ where } /// A curve that combines the output data from two constituent curves into a tuple output. Curves -/// of this type are produced by [`Curve::zip`]. +/// of this type are produced by [`CurveExt::zip`]. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -503,7 +506,7 @@ where /// For this to be well-formed, the first curve's domain must be right-finite and the second's /// must be left-finite. /// -/// Curves of this type are produced by [`Curve::chain`]. +/// Curves of this type are produced by [`CurveExt::chain`]. #[derive(Clone, Debug)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -549,7 +552,7 @@ where /// The curve that results from reversing another. /// -/// Curves of this type are produced by [`Curve::reverse`]. +/// Curves of this type are produced by [`CurveExt::reverse`]. /// /// # Domain /// @@ -590,7 +593,7 @@ where /// - the value at the transitioning points (`domain.end() * n` for `n >= 1`) in the results is the /// value at `domain.end()` in the original curve /// -/// Curves of this type are produced by [`Curve::repeat`]. +/// Curves of this type are produced by [`CurveExt::repeat`]. /// /// # Domain /// @@ -649,7 +652,7 @@ where /// - the value at the transitioning points (`domain.end() * n` for `n >= 1`) in the results is the /// value at `domain.end()` in the original curve /// -/// Curves of this type are produced by [`Curve::forever`]. +/// Curves of this type are produced by [`CurveExt::forever`]. /// /// # Domain /// @@ -703,7 +706,7 @@ where /// The curve that results from chaining a curve with its reversed version. The transition point /// is guaranteed to make no jump. /// -/// Curves of this type are produced by [`Curve::ping_pong`]. +/// Curves of this type are produced by [`CurveExt::ping_pong`]. /// /// # Domain /// @@ -756,7 +759,7 @@ where /// realized by translating the second curve so that its start sample point coincides with the /// first curves' end sample point. /// -/// Curves of this type are produced by [`Curve::chain_continue`]. +/// Curves of this type are produced by [`CurveExt::chain_continue`]. /// /// # Domain /// diff --git a/crates/bevy_math/src/curve/cores.rs b/crates/bevy_math/src/curve/cores.rs index 07330456570fe..a88aecfb674b5 100644 --- a/crates/bevy_math/src/curve/cores.rs +++ b/crates/bevy_math/src/curve/cores.rs @@ -432,14 +432,14 @@ impl UnevenCore { } /// This core, but with the sample times moved by the map `f`. - /// In principle, when `f` is monotone, this is equivalent to [`Curve::reparametrize`], + /// In principle, when `f` is monotone, this is equivalent to [`CurveExt::reparametrize`], /// but the function inputs to each are inverses of one another. /// /// The samples are re-sorted by time after mapping and deduplicated by output time, so /// the function `f` should generally be injective over the set of sample times, otherwise /// data will be deleted. /// - /// [`Curve::reparametrize`]: crate::curve::Curve::reparametrize + /// [`CurveExt::reparametrize`]: crate::curve::CurveExt::reparametrize #[must_use] pub fn map_sample_times(mut self, f: impl Fn(f32) -> f32) -> UnevenCore { let mut timed_samples = self diff --git a/crates/bevy_math/src/curve/derivatives/adaptor_impls.rs b/crates/bevy_math/src/curve/derivatives/adaptor_impls.rs index 6a32f1bb20e4f..a499526b78338 100644 --- a/crates/bevy_math/src/curve/derivatives/adaptor_impls.rs +++ b/crates/bevy_math/src/curve/derivatives/adaptor_impls.rs @@ -453,7 +453,7 @@ mod tests { use super::*; use crate::cubic_splines::{CubicBezier, CubicCardinalSpline, CubicCurve, CubicGenerator}; - use crate::curve::{Curve, Interval}; + use crate::curve::{Curve, CurveExt, Interval}; use crate::{vec2, Vec2, Vec3}; fn test_curve() -> CubicCurve { diff --git a/crates/bevy_math/src/curve/derivatives/mod.rs b/crates/bevy_math/src/curve/derivatives/mod.rs index e3b9e531dbed2..d819443f0d4f4 100644 --- a/crates/bevy_math/src/curve/derivatives/mod.rs +++ b/crates/bevy_math/src/curve/derivatives/mod.rs @@ -20,7 +20,7 @@ //! counterpart. //! //! [`with_derivative`]: CurveWithDerivative::with_derivative -//! [`by_ref`]: Curve::by_ref +//! [`by_ref`]: crate::curve::CurveExt::by_ref pub mod adaptor_impls; diff --git a/crates/bevy_math/src/curve/easing.rs b/crates/bevy_math/src/curve/easing.rs index 9a5ee27c01083..4e932a0a822c5 100644 --- a/crates/bevy_math/src/curve/easing.rs +++ b/crates/bevy_math/src/curve/easing.rs @@ -4,8 +4,8 @@ //! [easing functions]: EaseFunction use crate::{ - curve::{FunctionCurve, Interval}, - Curve, Dir2, Dir3, Dir3A, Quat, Rot2, VectorSpace, + curve::{Curve, CurveExt, FunctionCurve, Interval}, + Dir2, Dir3, Dir3A, Quat, Rot2, VectorSpace, }; use variadics_please::all_tuples_enumerated; diff --git a/crates/bevy_math/src/curve/mod.rs b/crates/bevy_math/src/curve/mod.rs index fa8636338f40f..43548f0893f56 100644 --- a/crates/bevy_math/src/curve/mod.rs +++ b/crates/bevy_math/src/curve/mod.rs @@ -269,18 +269,18 @@ //! //! [domain]: Curve::domain //! [sampled]: Curve::sample -//! [changing parametrizations]: Curve::reparametrize -//! [mapping output]: Curve::map -//! [rasterization]: Curve::resample +//! [changing parametrizations]: CurveExt::reparametrize +//! [mapping output]: CurveExt::map +//! [rasterization]: CurveResampleExt::resample //! [functions]: FunctionCurve //! [sample interpolation]: SampleCurve //! [splines]: crate::cubic_splines //! [easings]: easing //! [spline curves]: crate::cubic_splines //! [easing curves]: easing -//! [`chain`]: Curve::chain -//! [`zip`]: Curve::zip -//! [`resample`]: Curve::resample +//! [`chain`]: CurveExt::chain +//! [`zip`]: CurveExt::zip +//! [`resample`]: CurveResampleExt::resample //! //! [^footnote]: In fact, universal as well, in some sense: if `curve` is any curve, then `FunctionCurve::new //! (curve.domain(), |t| curve.sample_unchecked(t))` is an equivalent function curve. @@ -302,9 +302,7 @@ pub use interval::{interval, Interval}; #[cfg(feature = "alloc")] pub use { - crate::StableInterpolate, cores::{EvenCore, UnevenCore}, - itertools::Itertools, sample_curves::*, }; @@ -313,6 +311,9 @@ use core::{marker::PhantomData, ops::Deref}; use interval::InvalidIntervalError; use thiserror::Error; +#[cfg(feature = "alloc")] +use {crate::StableInterpolate, itertools::Itertools}; + /// A trait for a type that can represent values of type `T` parametrized over a fixed interval. /// /// Typical examples of this are actual geometric curves where `T: VectorSpace`, but other kinds @@ -349,17 +350,41 @@ pub trait Curve { let t = self.domain().clamp(t); self.sample_unchecked(t) } +} + +impl Curve for D +where + C: Curve + ?Sized, + D: Deref, +{ + fn domain(&self) -> Interval { + >::domain(self) + } + fn sample_unchecked(&self, t: f32) -> T { + >::sample_unchecked(self, t) + } +} + +/// Extension trait implemented by [curves], allowing access to a number of adaptors and +/// convenience methods. +/// +/// This trait is automatically implemented for all curves that are `Sized`. In particular, +/// it is implemented for types like `Box>`. `CurveExt` is not dyn-compatible +/// itself. +/// +/// For more information, see the [module-level documentation]. +/// +/// [curves]: Curve +/// [module-level documentation]: self +pub trait CurveExt: Curve + Sized { /// Sample a collection of `n >= 0` points on this curve at the parameter values `t_n`, /// returning `None` if the point is outside of the curve's domain. /// /// The samples are returned in the same order as the parameter values `t_n` were provided and /// will include all results. This leaves the responsibility for things like filtering and /// sorting to the user for maximum flexibility. - fn sample_iter(&self, iter: impl IntoIterator) -> impl Iterator> - where - Self: Sized, - { + fn sample_iter(&self, iter: impl IntoIterator) -> impl Iterator> { iter.into_iter().map(|t| self.sample(t)) } @@ -374,10 +399,10 @@ pub trait Curve { /// The samples are returned in the same order as the parameter values `t_n` were provided and /// will include all results. This leaves the responsibility for things like filtering and /// sorting to the user for maximum flexibility. - fn sample_iter_unchecked(&self, iter: impl IntoIterator) -> impl Iterator - where - Self: Sized, - { + fn sample_iter_unchecked( + &self, + iter: impl IntoIterator, + ) -> impl Iterator { iter.into_iter().map(|t| self.sample_unchecked(t)) } @@ -387,10 +412,7 @@ pub trait Curve { /// The samples are returned in the same order as the parameter values `t_n` were provided and /// will include all results. This leaves the responsibility for things like filtering and /// sorting to the user for maximum flexibility. - fn sample_iter_clamped(&self, iter: impl IntoIterator) -> impl Iterator - where - Self: Sized, - { + fn sample_iter_clamped(&self, iter: impl IntoIterator) -> impl Iterator { iter.into_iter().map(|t| self.sample_clamped(t)) } @@ -400,7 +422,6 @@ pub trait Curve { #[must_use] fn map(self, f: F) -> MapCurve where - Self: Sized, F: Fn(T) -> S, { MapCurve { @@ -425,7 +446,7 @@ pub trait Curve { /// let scaled_curve = my_curve.reparametrize(interval(0.0, 2.0).unwrap(), |t| t / 2.0); /// ``` /// This kind of linear remapping is provided by the convenience method - /// [`Curve::reparametrize_linear`], which requires only the desired domain for the new curve. + /// [`CurveExt::reparametrize_linear`], which requires only the desired domain for the new curve. /// /// # Examples /// ``` @@ -443,7 +464,6 @@ pub trait Curve { #[must_use] fn reparametrize(self, domain: Interval, f: F) -> ReparamCurve where - Self: Sized, F: Fn(f32) -> f32, { ReparamCurve { @@ -456,15 +476,15 @@ pub trait Curve { /// Linearly reparametrize this [`Curve`], producing a new curve whose domain is the given /// `domain` instead of the current one. This operation is only valid for curves with bounded - /// domains; if either this curve's domain or the given `domain` is unbounded, an error is - /// returned. + /// domains. + /// + /// # Errors + /// + /// If either this curve's domain or the given `domain` is unbounded, an error is returned. fn reparametrize_linear( self, domain: Interval, - ) -> Result, LinearReparamError> - where - Self: Sized, - { + ) -> Result, LinearReparamError> { if !self.domain().is_bounded() { return Err(LinearReparamError::SourceCurveUnbounded); } @@ -488,7 +508,6 @@ pub trait Curve { #[must_use] fn reparametrize_by_curve(self, other: C) -> CurveReparamCurve where - Self: Sized, C: Curve, { CurveReparamCurve { @@ -505,10 +524,7 @@ pub trait Curve { /// `(t, x)` at time `t`. In particular, if this curve is a `Curve`, the output of this method /// is a `Curve<(f32, T)>`. #[must_use] - fn graph(self) -> GraphCurve - where - Self: Sized, - { + fn graph(self) -> GraphCurve { GraphCurve { base: self, _phantom: PhantomData, @@ -519,11 +535,13 @@ pub trait Curve { /// /// The sample at time `t` in the new curve is `(x, y)`, where `x` is the sample of `self` at /// time `t` and `y` is the sample of `other` at time `t`. The domain of the new curve is the - /// intersection of the domains of its constituents. If the domain intersection would be empty, - /// an error is returned. + /// intersection of the domains of its constituents. + /// + /// # Errors + /// + /// If the domain intersection would be empty, an error is returned instead. fn zip(self, other: C) -> Result, InvalidIntervalError> where - Self: Sized, C: Curve + Sized, { let domain = self.domain().intersect(other.domain())?; @@ -545,7 +563,6 @@ pub trait Curve { /// `other`'s domain doesn't have a finite start. fn chain(self, other: C) -> Result, ChainError> where - Self: Sized, C: Curve, { if !self.domain().has_finite_end() { @@ -566,13 +583,10 @@ pub trait Curve { /// and transitioning over to `self.domain().start()`. The domain of the new curve is still the /// same. /// - /// # Error + /// # Errors /// /// A [`ReverseError`] is returned if this curve's domain isn't bounded. - fn reverse(self) -> Result, ReverseError> - where - Self: Sized, - { + fn reverse(self) -> Result, ReverseError> { self.domain() .is_bounded() .then(|| ReverseCurve { @@ -593,13 +607,10 @@ pub trait Curve { /// - the value at the transitioning points (`domain.end() * n` for `n >= 1`) in the results is the /// value at `domain.end()` in the original curve /// - /// # Error + /// # Errors /// /// A [`RepeatError`] is returned if this curve's domain isn't bounded. - fn repeat(self, count: usize) -> Result, RepeatError> - where - Self: Sized, - { + fn repeat(self, count: usize) -> Result, RepeatError> { self.domain() .is_bounded() .then(|| { @@ -629,13 +640,10 @@ pub trait Curve { /// - the value at the transitioning points (`domain.end() * n` for `n >= 1`) in the results is the /// value at `domain.end()` in the original curve /// - /// # Error + /// # Errors /// /// A [`RepeatError`] is returned if this curve's domain isn't bounded. - fn forever(self) -> Result, RepeatError> - where - Self: Sized, - { + fn forever(self) -> Result, RepeatError> { self.domain() .is_bounded() .then(|| ForeverCurve { @@ -649,13 +657,10 @@ pub trait Curve { /// another curve with outputs of the same type. The domain of the new curve will be twice as /// long. The transition point is guaranteed to not make any jumps. /// - /// # Error + /// # Errors /// /// A [`PingPongError`] is returned if this curve's domain isn't right-finite. - fn ping_pong(self) -> Result, PingPongError> - where - Self: Sized, - { + fn ping_pong(self) -> Result, PingPongError> { self.domain() .has_finite_end() .then(|| PingPongCurve { @@ -676,13 +681,12 @@ pub trait Curve { /// realized by translating the other curve so that its start sample point coincides with the /// current curves' end sample point. /// - /// # Error + /// # Errors /// /// A [`ChainError`] is returned if this curve's domain doesn't have a finite end or if /// `other`'s domain doesn't have a finite start. fn chain_continue(self, other: C) -> Result, ChainError> where - Self: Sized, T: VectorSpace, C: Curve, { @@ -704,17 +708,88 @@ pub trait Curve { }) } + /// Extract an iterator over evenly-spaced samples from this curve. + /// + /// # Errors + /// + /// If `samples` is less than 2 or if this curve has unbounded domain, a [`ResamplingError`] + /// is returned. + fn samples(&self, samples: usize) -> Result, ResamplingError> { + if samples < 2 { + return Err(ResamplingError::NotEnoughSamples(samples)); + } + if !self.domain().is_bounded() { + return Err(ResamplingError::UnboundedDomain); + } + + // Unwrap on `spaced_points` always succeeds because its error conditions are handled + // above. + Ok(self + .domain() + .spaced_points(samples) + .unwrap() + .map(|t| self.sample_unchecked(t))) + } + + /// Borrow this curve rather than taking ownership of it. This is essentially an alias for a + /// prefix `&`; the point is that intermediate operations can be performed while retaining + /// access to the original curve. + /// + /// # Example + /// ``` + /// # use bevy_math::curve::*; + /// let my_curve = FunctionCurve::new(Interval::UNIT, |t| t * t + 1.0); + /// + /// // Borrow `my_curve` long enough to resample a mapped version. Note that `map` takes + /// // ownership of its input. + /// let samples = my_curve.by_ref().map(|x| x * 2.0).resample_auto(100).unwrap(); + /// + /// // Do something else with `my_curve` since we retained ownership: + /// let new_curve = my_curve.reparametrize_linear(interval(-1.0, 1.0).unwrap()).unwrap(); + /// ``` + fn by_ref(&self) -> &Self { + self + } + + /// Flip this curve so that its tuple output is arranged the other way. + #[must_use] + fn flip(self) -> impl Curve<(V, U)> + where + Self: CurveExt<(U, V)>, + { + self.map(|(u, v)| (v, u)) + } +} + +impl CurveExt for C where C: Curve {} + +/// Extension trait implemented by [curves], allowing access to generic resampling methods as +/// well as those based on [stable interpolation]. +/// +/// This trait is automatically implemented for all curves. +/// +/// For more information, see the [module-level documentation]. +/// +/// [curves]: Curve +/// [stable interpolation]: crate::StableInterpolate +/// [module-level documentation]: self +#[cfg(feature = "alloc")] +pub trait CurveResampleExt: Curve { /// Resample this [`Curve`] to produce a new one that is defined by interpolation over equally /// spaced sample values, using the provided `interpolation` to interpolate between adjacent samples. /// The curve is interpolated on `segments` segments between samples. For example, if `segments` is 1, /// only the start and end points of the curve are used as samples; if `segments` is 2, a sample at - /// the midpoint is taken as well, and so on. If `segments` is zero, or if this curve has an unbounded - /// domain, then a [`ResamplingError`] is returned. + /// the midpoint is taken as well, and so on. /// /// The interpolation takes two values by reference together with a scalar parameter and /// produces an owned value. The expectation is that `interpolation(&x, &y, 0.0)` and /// `interpolation(&x, &y, 1.0)` are equivalent to `x` and `y` respectively. /// + /// # Errors + /// + /// If `segments` is zero or if this curve has unbounded domain, then a [`ResamplingError`] is + /// returned. + /// /// # Example /// ``` /// # use bevy_math::*; @@ -723,14 +798,12 @@ pub trait Curve { /// // A curve which only stores three data points and uses `nlerp` to interpolate them: /// let resampled_rotation = quarter_rotation.resample(3, |x, y, t| x.nlerp(*y, t)); /// ``` - #[cfg(feature = "alloc")] fn resample( &self, segments: usize, interpolation: I, ) -> Result, ResamplingError> where - Self: Sized, I: Fn(&T, &T, f32) -> T, { let samples = self.samples(segments + 1)?.collect_vec(); @@ -747,14 +820,15 @@ pub trait Curve { /// spaced sample values, using [automatic interpolation] to interpolate between adjacent samples. /// The curve is interpolated on `segments` segments between samples. For example, if `segments` is 1, /// only the start and end points of the curve are used as samples; if `segments` is 2, a sample at - /// the midpoint is taken as well, and so on. If `segments` is zero, or if this curve has an unbounded - /// domain, then a [`ResamplingError`] is returned. + /// the midpoint is taken as well, and so on. + /// + /// # Errors + /// + /// If `segments` is zero or if this curve has unbounded domain, a [`ResamplingError`] is returned. /// /// [automatic interpolation]: crate::common_traits::StableInterpolate - #[cfg(feature = "alloc")] fn resample_auto(&self, segments: usize) -> Result, ResamplingError> where - Self: Sized, T: StableInterpolate, { let samples = self.samples(segments + 1)?.collect_vec(); @@ -766,35 +840,13 @@ pub trait Curve { }) } - /// Extract an iterator over evenly-spaced samples from this curve. If `samples` is less than 2 - /// or if this curve has unbounded domain, then an error is returned instead. - fn samples(&self, samples: usize) -> Result, ResamplingError> - where - Self: Sized, - { - if samples < 2 { - return Err(ResamplingError::NotEnoughSamples(samples)); - } - if !self.domain().is_bounded() { - return Err(ResamplingError::UnboundedDomain); - } - - // Unwrap on `spaced_points` always succeeds because its error conditions are handled - // above. - Ok(self - .domain() - .spaced_points(samples) - .unwrap() - .map(|t| self.sample_unchecked(t))) - } - /// Resample this [`Curve`] to produce a new one that is defined by interpolation over samples /// taken at a given set of times. The given `interpolation` is used to interpolate adjacent /// samples, and the `sample_times` are expected to contain at least two valid times within the /// curve's domain interval. /// /// Redundant sample times, non-finite sample times, and sample times outside of the domain - /// are simply filtered out. With an insufficient quantity of data, a [`ResamplingError`] is + /// are filtered out. With an insufficient quantity of data, a [`ResamplingError`] is /// returned. /// /// The domain of the produced curve stretches between the first and last sample times of the @@ -803,14 +855,17 @@ pub trait Curve { /// The interpolation takes two values by reference together with a scalar parameter and /// produces an owned value. The expectation is that `interpolation(&x, &y, 0.0)` and /// `interpolation(&x, &y, 1.0)` are equivalent to `x` and `y` respectively. - #[cfg(feature = "alloc")] + /// + /// # Errors + /// + /// If `sample_times` doesn't contain at least two distinct times after filtering, a + /// [`ResamplingError`] is returned. fn resample_uneven( &self, sample_times: impl IntoIterator, interpolation: I, ) -> Result, ResamplingError> where - Self: Sized, I: Fn(&T, &T, f32) -> T, { let domain = self.domain(); @@ -841,14 +896,17 @@ pub trait Curve { /// The domain of the produced [`UnevenSampleAutoCurve`] stretches between the first and last /// sample times of the iterator. /// + /// # Errors + /// + /// If `sample_times` doesn't contain at least two distinct times after filtering, a + /// [`ResamplingError`] is returned. + /// /// [automatic interpolation]: crate::common_traits::StableInterpolate - #[cfg(feature = "alloc")] fn resample_uneven_auto( &self, sample_times: impl IntoIterator, ) -> Result, ResamplingError> where - Self: Sized, T: StableInterpolate, { let domain = self.domain(); @@ -866,53 +924,10 @@ pub trait Curve { core: UnevenCore { times, samples }, }) } - - /// Borrow this curve rather than taking ownership of it. This is essentially an alias for a - /// prefix `&`; the point is that intermediate operations can be performed while retaining - /// access to the original curve. - /// - /// # Example - /// ``` - /// # use bevy_math::curve::*; - /// let my_curve = FunctionCurve::new(Interval::UNIT, |t| t * t + 1.0); - /// - /// // Borrow `my_curve` long enough to resample a mapped version. Note that `map` takes - /// // ownership of its input. - /// let samples = my_curve.by_ref().map(|x| x * 2.0).resample_auto(100).unwrap(); - /// - /// // Do something else with `my_curve` since we retained ownership: - /// let new_curve = my_curve.reparametrize_linear(interval(-1.0, 1.0).unwrap()).unwrap(); - /// ``` - fn by_ref(&self) -> &Self - where - Self: Sized, - { - self - } - - /// Flip this curve so that its tuple output is arranged the other way. - #[must_use] - fn flip(self) -> impl Curve<(V, U)> - where - Self: Sized + Curve<(U, V)>, - { - self.map(|(u, v)| (v, u)) - } } -impl Curve for D -where - C: Curve + ?Sized, - D: Deref, -{ - fn domain(&self) -> Interval { - >::domain(self) - } - - fn sample_unchecked(&self, t: f32) -> T { - >::sample_unchecked(self, t) - } -} +#[cfg(feature = "alloc")] +impl CurveResampleExt for C where C: Curve + ?Sized {} /// An error indicating that a linear reparameterization couldn't be performed because of /// malformed inputs. diff --git a/crates/bevy_math/src/curve/sample_curves.rs b/crates/bevy_math/src/curve/sample_curves.rs index 7a37f55640090..15ca51c2a3ba8 100644 --- a/crates/bevy_math/src/curve/sample_curves.rs +++ b/crates/bevy_math/src/curve/sample_curves.rs @@ -285,11 +285,13 @@ impl UnevenSampleCurve { } /// This [`UnevenSampleAutoCurve`], but with the sample times moved by the map `f`. - /// In principle, when `f` is monotone, this is equivalent to [`Curve::reparametrize`], + /// In principle, when `f` is monotone, this is equivalent to [`CurveExt::reparametrize`], /// but the function inputs to each are inverses of one another. /// /// The samples are re-sorted by time after mapping and deduplicated by output time, so /// the function `f` should generally be injective over the sample times of the curve. + /// + /// [`CurveExt::reparametrize`]: super::CurveExt::reparametrize pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleCurve { Self { core: self.core.map_sample_times(f), @@ -343,11 +345,13 @@ impl UnevenSampleAutoCurve { } /// This [`UnevenSampleAutoCurve`], but with the sample times moved by the map `f`. - /// In principle, when `f` is monotone, this is equivalent to [`Curve::reparametrize`], + /// In principle, when `f` is monotone, this is equivalent to [`CurveExt::reparametrize`], /// but the function inputs to each are inverses of one another. /// /// The samples are re-sorted by time after mapping and deduplicated by output time, so /// the function `f` should generally be injective over the sample times of the curve. + /// + /// [`CurveExt::reparametrize`]: super::CurveExt::reparametrize pub fn map_sample_times(self, f: impl Fn(f32) -> f32) -> UnevenSampleAutoCurve { Self { core: self.core.map_sample_times(f), From 847c3a1719ff622a9059910836e6f8134401cf9a Mon Sep 17 00:00:00 2001 From: Benjamin Brienen Date: Sun, 29 Dec 2024 14:28:59 -0500 Subject: [PATCH 04/11] Fix random clippy warning (#17010) # Objective Follow-up to #16984 ## Solution Fix the lint ## Testing ``` PS C:\Users\BenjaminBrienen\source\bevy> cargo clippy Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.71s PS C:\Users\BenjaminBrienen\source\bevy> cargo clippy -p bevy_ecs Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21s ``` --- crates/bevy_ecs/Cargo.toml | 4 ++-- crates/bevy_ecs/src/entity/clone_entities.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index add6ff18615f7..e32b51a916637 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["ecs", "game", "bevy"] categories = ["game-engines", "data-structures"] -rust-version = "1.81.0" +rust-version = "1.82.0" [features] default = ["std", "bevy_reflect", "async_executor"] @@ -84,7 +84,7 @@ critical-section = [ ] ## `portable-atomic` provides additional platform support for atomic types and -## operations, even on targets without native support. +## operations, even on targets without native support. portable-atomic = [ "dep:portable-atomic", "dep:portable-atomic-util", diff --git a/crates/bevy_ecs/src/entity/clone_entities.rs b/crates/bevy_ecs/src/entity/clone_entities.rs index b15723aa57419..4a326cc955d75 100644 --- a/crates/bevy_ecs/src/entity/clone_entities.rs +++ b/crates/bevy_ecs/src/entity/clone_entities.rs @@ -147,10 +147,10 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> { if self.target_component_written { panic!("Trying to write component '{short_name}' multiple times") } - if !self + if self .component_info .type_id() - .is_some_and(|id| id == TypeId::of::()) + .is_none_or(|id| id != TypeId::of::()) { panic!("TypeId of component '{short_name}' does not match source component TypeId") }; From 5157c78651c07993de1b7c22b07d31bb4aa8fe95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Maita?= <47983254+mnmaita@users.noreply.github.com> Date: Sun, 29 Dec 2024 20:29:53 +0100 Subject: [PATCH 05/11] Move `futures.rs`, `ConditionalSend` and `BoxedFuture` types to `bevy_tasks` (#16951) # Objective - Related to https://github.com/bevyengine/bevy/issues/11478 ## Solution - Moved `futures.rs`, `ConditionalSend` `ConditionalSendFuture` and `BoxedFuture` from `bevy_utils` to `bevy_tasks`. ## Testing - CI checks ## Migration Guide - Several modules were moved from `bevy_utils` into `bevy_tasks`: - Replace `bevy_utils::futures` imports with `bevy_tasks::futures`. - Replace `bevy_utils::ConditionalSend` with `bevy_tasks::ConditionalSend`. - Replace `bevy_utils::ConditionalSendFuture` with `bevy_tasks::ConditionalSendFuture`. - Replace `bevy_utils::BoxedFuture` with `bevy_tasks::BoxedFuture`. --- crates/bevy_asset/src/io/mod.rs | 2 +- crates/bevy_asset/src/loader.rs | 3 +- crates/bevy_asset/src/processor/mod.rs | 9 +++--- crates/bevy_asset/src/processor/process.rs | 2 +- crates/bevy_asset/src/saver.rs | 3 +- crates/bevy_asset/src/server/loaders.rs | 9 +++--- crates/bevy_asset/src/transformer.rs | 3 +- .../src/render_resource/pipeline_cache.rs | 4 +-- .../{bevy_utils => bevy_tasks}/src/futures.rs | 2 ++ crates/bevy_tasks/src/lib.rs | 29 +++++++++++++++++ crates/bevy_utils/src/lib.rs | 32 +------------------ 11 files changed, 50 insertions(+), 48 deletions(-) rename crates/{bevy_utils => bevy_tasks}/src/futures.rs (96%) diff --git a/crates/bevy_asset/src/io/mod.rs b/crates/bevy_asset/src/io/mod.rs index 0c4c0b1f00356..f6d567e78906a 100644 --- a/crates/bevy_asset/src/io/mod.rs +++ b/crates/bevy_asset/src/io/mod.rs @@ -22,7 +22,7 @@ pub use futures_lite::AsyncWriteExt; pub use source::*; use alloc::sync::Arc; -use bevy_utils::{BoxedFuture, ConditionalSendFuture}; +use bevy_tasks::{BoxedFuture, ConditionalSendFuture}; use core::future::Future; use core::{ mem::size_of, diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index bfd5064138929..96515460e494a 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -8,7 +8,8 @@ use crate::{ }; use atomicow::CowArc; use bevy_ecs::world::World; -use bevy_utils::{BoxedFuture, ConditionalSendFuture, HashMap, HashSet}; +use bevy_tasks::{BoxedFuture, ConditionalSendFuture}; +use bevy_utils::{HashMap, HashSet}; use core::any::{Any, TypeId}; use downcast_rs::{impl_downcast, Downcast}; use ron::error::SpannedError; diff --git a/crates/bevy_asset/src/processor/mod.rs b/crates/bevy_asset/src/processor/mod.rs index c1e9999bd017a..26bde8cd33b9a 100644 --- a/crates/bevy_asset/src/processor/mod.rs +++ b/crates/bevy_asset/src/processor/mod.rs @@ -58,16 +58,15 @@ use crate::{ }; use alloc::{collections::VecDeque, sync::Arc}; use bevy_ecs::prelude::*; +#[cfg(feature = "trace")] +use bevy_tasks::ConditionalSendFuture; use bevy_tasks::IoTaskPool; +#[cfg(feature = "trace")] +use bevy_utils::tracing::{info_span, instrument::Instrument}; use bevy_utils::{ tracing::{debug, error, trace, warn}, HashMap, HashSet, }; -#[cfg(feature = "trace")] -use bevy_utils::{ - tracing::{info_span, instrument::Instrument}, - ConditionalSendFuture, -}; use futures_io::ErrorKind; use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt}; use parking_lot::RwLock; diff --git a/crates/bevy_asset/src/processor/process.rs b/crates/bevy_asset/src/processor/process.rs index 64370824dc630..77c70f636fffe 100644 --- a/crates/bevy_asset/src/processor/process.rs +++ b/crates/bevy_asset/src/processor/process.rs @@ -10,7 +10,7 @@ use crate::{ AssetLoadError, AssetLoader, AssetPath, DeserializeMetaError, ErasedLoadedAsset, MissingAssetLoaderForExtensionError, MissingAssetLoaderForTypeNameError, }; -use bevy_utils::{BoxedFuture, ConditionalSendFuture}; +use bevy_tasks::{BoxedFuture, ConditionalSendFuture}; use core::marker::PhantomData; use serde::{Deserialize, Serialize}; use thiserror::Error; diff --git a/crates/bevy_asset/src/saver.rs b/crates/bevy_asset/src/saver.rs index f2cb5bb9330f9..d1f907e07e86e 100644 --- a/crates/bevy_asset/src/saver.rs +++ b/crates/bevy_asset/src/saver.rs @@ -3,7 +3,8 @@ use crate::{ ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle, }; use atomicow::CowArc; -use bevy_utils::{BoxedFuture, ConditionalSendFuture, HashMap}; +use bevy_tasks::{BoxedFuture, ConditionalSendFuture}; +use bevy_utils::HashMap; use core::{borrow::Borrow, hash::Hash, ops::Deref}; use serde::{Deserialize, Serialize}; diff --git a/crates/bevy_asset/src/server/loaders.rs b/crates/bevy_asset/src/server/loaders.rs index 2442de389ae3d..007dea47b0504 100644 --- a/crates/bevy_asset/src/server/loaders.rs +++ b/crates/bevy_asset/src/server/loaders.rs @@ -4,13 +4,12 @@ use crate::{ }; use alloc::sync::Arc; use async_broadcast::RecvError; +#[cfg(feature = "trace")] +use bevy_tasks::ConditionalSendFuture; use bevy_tasks::IoTaskPool; -use bevy_utils::{tracing::warn, HashMap, TypeIdMap}; #[cfg(feature = "trace")] -use bevy_utils::{ - tracing::{info_span, instrument::Instrument}, - ConditionalSendFuture, -}; +use bevy_utils::tracing::{info_span, instrument::Instrument}; +use bevy_utils::{tracing::warn, HashMap, TypeIdMap}; use core::any::TypeId; use thiserror::Error; diff --git a/crates/bevy_asset/src/transformer.rs b/crates/bevy_asset/src/transformer.rs index 484e02003f644..ac894ea69fcad 100644 --- a/crates/bevy_asset/src/transformer.rs +++ b/crates/bevy_asset/src/transformer.rs @@ -1,6 +1,7 @@ use crate::{meta::Settings, Asset, ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle}; use atomicow::CowArc; -use bevy_utils::{ConditionalSendFuture, HashMap}; +use bevy_tasks::ConditionalSendFuture; +use bevy_utils::HashMap; use core::{ borrow::Borrow, convert::Infallible, diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index b4a7514d1d164..220f5bd326af5 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -329,7 +329,7 @@ impl ShaderCache { // So to keep the complexity of the ShaderCache low, we will only catch this error early on native platforms, // and on wasm the error will be handled by wgpu and crash the application. if let Some(Some(wgpu::Error::Validation { description, .. })) = - bevy_utils::futures::now_or_never(error) + bevy_tasks::futures::now_or_never(error) { return Err(PipelineCacheError::CreateShaderModule(description)); } @@ -874,7 +874,7 @@ impl PipelineCache { } CachedPipelineState::Creating(ref mut task) => { - match bevy_utils::futures::check_ready(task) { + match bevy_tasks::futures::check_ready(task) { Some(Ok(pipeline)) => { cached_pipeline.state = CachedPipelineState::Ok(pipeline); return; diff --git a/crates/bevy_utils/src/futures.rs b/crates/bevy_tasks/src/futures.rs similarity index 96% rename from crates/bevy_utils/src/futures.rs rename to crates/bevy_tasks/src/futures.rs index 6a4f9ff9cc9e4..a28138e0ecaa2 100644 --- a/crates/bevy_utils/src/futures.rs +++ b/crates/bevy_tasks/src/futures.rs @@ -1,3 +1,5 @@ +#![expect(unsafe_code, reason = "Futures require unsafe code.")] + //! Utilities for working with [`Future`]s. use core::{ future::Future, diff --git a/crates/bevy_tasks/src/lib.rs b/crates/bevy_tasks/src/lib.rs index 3f3db301bbb00..1be5761bd0f86 100644 --- a/crates/bevy_tasks/src/lib.rs +++ b/crates/bevy_tasks/src/lib.rs @@ -8,6 +8,35 @@ extern crate alloc; +#[cfg(not(target_arch = "wasm32"))] +mod conditional_send { + /// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm), + /// futures aren't Send. + pub trait ConditionalSend: Send {} + impl ConditionalSend for T {} +} + +#[cfg(target_arch = "wasm32")] +#[expect(missing_docs, reason = "Not all docs are written yet (#3492).")] +mod conditional_send { + pub trait ConditionalSend {} + impl ConditionalSend for T {} +} + +pub use conditional_send::*; + +/// Use [`ConditionalSendFuture`] for a future with an optional Send trait bound, as on certain platforms (eg. Wasm), +/// futures aren't Send. +pub trait ConditionalSendFuture: core::future::Future + ConditionalSend {} +impl ConditionalSendFuture for T {} + +use alloc::boxed::Box; + +/// An owned and dynamically typed Future used when you can't statically type your result or need to add some indirection. +pub type BoxedFuture<'a, T> = core::pin::Pin + 'a>>; + +pub mod futures; + mod executor; mod slice; diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index 4e344fc0cf76d..7b660ed70e6e3 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![expect( unsafe_code, - reason = "Some utilities, such as futures and cells, require unsafe code." + reason = "Some utilities, such as cells, require unsafe code." )] #![doc( html_logo_url = "https://bevyengine.org/assets/icon.png", @@ -23,7 +23,6 @@ pub mod prelude { pub use crate::default; } -pub mod futures; pub mod synccell; pub mod syncunsafecell; @@ -64,9 +63,6 @@ pub use time::*; #[cfg(feature = "tracing")] pub use tracing; -#[cfg(feature = "alloc")] -use alloc::boxed::Box; - #[cfg(feature = "alloc")] use core::any::TypeId; use core::{ @@ -77,32 +73,6 @@ use core::{ ops::Deref, }; -#[cfg(not(target_arch = "wasm32"))] -mod conditional_send { - /// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm), - /// futures aren't Send. - pub trait ConditionalSend: Send {} - impl ConditionalSend for T {} -} - -#[cfg(target_arch = "wasm32")] -#[expect(missing_docs, reason = "Not all docs are written yet (#3492).")] -mod conditional_send { - pub trait ConditionalSend {} - impl ConditionalSend for T {} -} - -pub use conditional_send::*; - -/// Use [`ConditionalSendFuture`] for a future with an optional Send trait bound, as on certain platforms (eg. Wasm), -/// futures aren't Send. -pub trait ConditionalSendFuture: core::future::Future + ConditionalSend {} -impl ConditionalSendFuture for T {} - -/// An owned and dynamically typed Future used when you can't statically type your result or need to add some indirection. -#[cfg(feature = "alloc")] -pub type BoxedFuture<'a, T> = core::pin::Pin + 'a>>; - /// A shortcut alias for [`hashbrown::hash_map::Entry`]. #[cfg(feature = "alloc")] pub type Entry<'a, K, V, S = FixedHasher> = hashbrown::hash_map::Entry<'a, K, V, S>; From 58a84d965e3a2e7f6a2a50c0b2cf755871b48698 Mon Sep 17 00:00:00 2001 From: Satellile <118775491+Satellile@users.noreply.github.com> Date: Sun, 29 Dec 2024 14:32:44 -0500 Subject: [PATCH 06/11] Fix Docs // incorrect default value for ChromaticAberration intensity (#16994) # Objective Incorrect default value for ChromatticAberration intensity, missing a zero. Bevy 0.15 --- crates/bevy_core_pipeline/src/post_process/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_core_pipeline/src/post_process/mod.rs b/crates/bevy_core_pipeline/src/post_process/mod.rs index a633134b276d2..f1719c1384222 100644 --- a/crates/bevy_core_pipeline/src/post_process/mod.rs +++ b/crates/bevy_core_pipeline/src/post_process/mod.rs @@ -112,7 +112,7 @@ pub struct ChromaticAberration { /// The size of the streaks around the edges of objects, as a fraction of /// the window size. /// - /// The default value is 0.2. + /// The default value is 0.02. pub intensity: f32, /// A cap on the number of texture samples that will be performed. From f391522483255a34fc792b2b242fe0e424a335b1 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sun, 29 Dec 2024 14:33:06 -0500 Subject: [PATCH 07/11] Test benchmarks in CI (#16987) # Objective - This reverts #16833, and completely goes against #16803. - Turns out running `cargo test --benches` runs each benchmark once, without timing it, just to ensure nothing panics. This is actually desired because we can use it to verify benchmarks are working correctly without all the time constraints of actual benchmarks. ## Solution - Add the `--benches` flag to the CI test command. ## Testing - `cargo run -p ci -- test` --- benches/benches/bevy_tasks/iter.rs | 4 ++-- tools/ci/src/commands/test.rs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/benches/benches/bevy_tasks/iter.rs b/benches/benches/bevy_tasks/iter.rs index 4f8f75c8ed0e8..47c2f6de14902 100644 --- a/benches/benches/bevy_tasks/iter.rs +++ b/benches/benches/bevy_tasks/iter.rs @@ -61,7 +61,7 @@ fn bench_for_each(c: &mut Criterion) { b.iter(|| { v.iter_mut().for_each(|x| { busy_work(10000); - *x *= *x; + *x = x.wrapping_mul(*x); }); }); }); @@ -77,7 +77,7 @@ fn bench_for_each(c: &mut Criterion) { b.iter(|| { ParChunksMut(v.chunks_mut(100)).for_each(&pool, |x| { busy_work(10000); - *x *= *x; + *x = x.wrapping_mul(*x); }); }); }, diff --git a/tools/ci/src/commands/test.rs b/tools/ci/src/commands/test.rs index 82a64e02a0c58..bdb4b663d1429 100644 --- a/tools/ci/src/commands/test.rs +++ b/tools/ci/src/commands/test.rs @@ -17,7 +17,9 @@ impl Prepare for TestCommand { vec![PreparedCommand::new::( cmd!( sh, - "cargo test --workspace --lib --bins --tests {no_fail_fast}" + // `--benches` runs each benchmark once in order to verify that they behave + // correctly and do not panic. + "cargo test --workspace --lib --bins --tests --benches {no_fail_fast}" ), "Please fix failing tests in output above.", )] From 17ad85565351d89ab41db11c25bb0cade5727eb3 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sun, 29 Dec 2024 14:33:42 -0500 Subject: [PATCH 08/11] Migrate to `core::hint::black_box()` (#16980) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective Many of our benchmarks use [`criterion::black_box()`](https://docs.rs/criterion/latest/criterion/fn.black_box.html), which is used to prevent the compiler from optimizing away computation that we're trying to time. This can be slow, though, because `criterion::black_box()` forces a point read each time it is called through [`ptr::road_volatile()`](https://doc.rust-lang.org/stable/std/ptr/fn.read_volatile.html). In Rust 1.66, the standard library introduced [`core::hint::black_box()`](https://doc.rust-lang.org/nightly/std/hint/fn.black_box.html) (and `std::hint::black_box()`). This is an intended replacement for `criterion`'s version that uses compiler intrinsics instead of volatile pointer reads, and thus has no runtime overhead. This increases benchmark accuracy, which is always nice 👍 Note that benchmarks may _appear_ to improve in performance after this change, but that's just because we are eliminating the pointer read overhead. ## Solution - Deny `criterion::black_box` in `clippy.toml`. - Fix all imports. ## Testing - `cargo clippy -p benches --benches` --- benches/benches/bevy_ecs/change_detection.rs | 4 +++- benches/benches/bevy_ecs/empty_archetypes.rs | 4 +++- benches/benches/bevy_ecs/entity_cloning.rs | 4 +++- benches/benches/bevy_ecs/observers/propagation.rs | 4 +++- benches/benches/bevy_ecs/observers/simple.rs | 4 +++- benches/benches/bevy_ecs/world/commands.rs | 4 +++- benches/benches/bevy_ecs/world/world_get.rs | 4 +++- benches/benches/bevy_math/bezier.rs | 4 +++- benches/benches/bevy_picking/ray_mesh_intersection.rs | 4 +++- benches/benches/bevy_reflect/list.rs | 6 +++--- benches/benches/bevy_reflect/map.rs | 6 +++--- benches/benches/bevy_reflect/path.rs | 4 ++-- benches/benches/bevy_reflect/struct.rs | 6 +++--- benches/benches/bevy_render/render_layers.rs | 4 +++- benches/benches/bevy_render/torus.rs | 4 +++- benches/benches/bevy_tasks/iter.rs | 4 +++- clippy.toml | 1 + 17 files changed, 48 insertions(+), 23 deletions(-) diff --git a/benches/benches/bevy_ecs/change_detection.rs b/benches/benches/bevy_ecs/change_detection.rs index ca57da93fabe6..8d49c2b8c7e1c 100644 --- a/benches/benches/bevy_ecs/change_detection.rs +++ b/benches/benches/bevy_ecs/change_detection.rs @@ -1,3 +1,5 @@ +use core::hint::black_box; + use bevy_ecs::{ component::{Component, Mutable}, entity::Entity, @@ -5,7 +7,7 @@ use bevy_ecs::{ query::QueryFilter, world::World, }; -use criterion::{black_box, criterion_group, Criterion}; +use criterion::{criterion_group, Criterion}; use rand::{prelude::SliceRandom, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/benches/benches/bevy_ecs/empty_archetypes.rs b/benches/benches/bevy_ecs/empty_archetypes.rs index daec970b74a87..91c2b5427a068 100644 --- a/benches/benches/bevy_ecs/empty_archetypes.rs +++ b/benches/benches/bevy_ecs/empty_archetypes.rs @@ -1,5 +1,7 @@ +use core::hint::black_box; + use bevy_ecs::{component::Component, prelude::*, schedule::ExecutorKind, world::World}; -use criterion::{black_box, criterion_group, BenchmarkId, Criterion}; +use criterion::{criterion_group, BenchmarkId, Criterion}; criterion_group!(benches, empty_archetypes); diff --git a/benches/benches/bevy_ecs/entity_cloning.rs b/benches/benches/bevy_ecs/entity_cloning.rs index 51af20b7b187d..218a551584cfb 100644 --- a/benches/benches/bevy_ecs/entity_cloning.rs +++ b/benches/benches/bevy_ecs/entity_cloning.rs @@ -1,10 +1,12 @@ +use core::hint::black_box; + use bevy_ecs::bundle::Bundle; use bevy_ecs::reflect::AppTypeRegistry; use bevy_ecs::{component::Component, reflect::ReflectComponent, world::World}; use bevy_hierarchy::{BuildChildren, CloneEntityHierarchyExt}; use bevy_math::Mat4; use bevy_reflect::{GetTypeRegistration, Reflect}; -use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; +use criterion::{criterion_group, criterion_main, Bencher, Criterion}; criterion_group!(benches, reflect_benches, clone_benches); criterion_main!(benches); diff --git a/benches/benches/bevy_ecs/observers/propagation.rs b/benches/benches/bevy_ecs/observers/propagation.rs index 5de85bc3269b2..1989c05fc62f7 100644 --- a/benches/benches/bevy_ecs/observers/propagation.rs +++ b/benches/benches/bevy_ecs/observers/propagation.rs @@ -1,9 +1,11 @@ +use core::hint::black_box; + use bevy_ecs::{ component::Component, entity::Entity, event::Event, observer::Trigger, world::World, }; use bevy_hierarchy::{BuildChildren, Parent}; -use criterion::{black_box, Criterion}; +use criterion::Criterion; use rand::SeedableRng; use rand::{seq::IteratorRandom, Rng}; use rand_chacha::ChaCha8Rng; diff --git a/benches/benches/bevy_ecs/observers/simple.rs b/benches/benches/bevy_ecs/observers/simple.rs index 81dd8e021e8ce..bf2dd236d60ea 100644 --- a/benches/benches/bevy_ecs/observers/simple.rs +++ b/benches/benches/bevy_ecs/observers/simple.rs @@ -1,6 +1,8 @@ +use core::hint::black_box; + use bevy_ecs::{entity::Entity, event::Event, observer::Trigger, world::World}; -use criterion::{black_box, Criterion}; +use criterion::Criterion; use rand::{prelude::SliceRandom, SeedableRng}; use rand_chacha::ChaCha8Rng; fn deterministic_rand() -> ChaCha8Rng { diff --git a/benches/benches/bevy_ecs/world/commands.rs b/benches/benches/bevy_ecs/world/commands.rs index a1d7cdb09e382..9f5a93bf141ad 100644 --- a/benches/benches/bevy_ecs/world/commands.rs +++ b/benches/benches/bevy_ecs/world/commands.rs @@ -1,9 +1,11 @@ +use core::hint::black_box; + use bevy_ecs::{ component::Component, system::Commands, world::{Command, CommandQueue, World}, }; -use criterion::{black_box, Criterion}; +use criterion::Criterion; #[derive(Component)] struct A; diff --git a/benches/benches/bevy_ecs/world/world_get.rs b/benches/benches/bevy_ecs/world/world_get.rs index 190402fbadb27..fcb9b0116bb95 100644 --- a/benches/benches/bevy_ecs/world/world_get.rs +++ b/benches/benches/bevy_ecs/world/world_get.rs @@ -1,3 +1,5 @@ +use core::hint::black_box; + use bevy_ecs::{ bundle::Bundle, component::Component, @@ -5,7 +7,7 @@ use bevy_ecs::{ system::{Query, SystemState}, world::World, }; -use criterion::{black_box, Criterion}; +use criterion::Criterion; use rand::{prelude::SliceRandom, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/benches/benches/bevy_math/bezier.rs b/benches/benches/bevy_math/bezier.rs index 404ab08a63eb2..1858a05466ae1 100644 --- a/benches/benches/bevy_math/bezier.rs +++ b/benches/benches/bevy_math/bezier.rs @@ -1,4 +1,6 @@ -use criterion::{black_box, criterion_group, Criterion}; +use core::hint::black_box; + +use criterion::{criterion_group, Criterion}; use bevy_math::prelude::*; diff --git a/benches/benches/bevy_picking/ray_mesh_intersection.rs b/benches/benches/bevy_picking/ray_mesh_intersection.rs index 1d019d43ee37f..e8b35078f70e1 100644 --- a/benches/benches/bevy_picking/ray_mesh_intersection.rs +++ b/benches/benches/bevy_picking/ray_mesh_intersection.rs @@ -1,6 +1,8 @@ +use core::hint::black_box; + use bevy_math::{Dir3, Mat4, Ray3d, Vec3}; use bevy_picking::mesh_picking::ray_cast; -use criterion::{black_box, criterion_group, Criterion}; +use criterion::{criterion_group, Criterion}; fn ptoxznorm(p: u32, size: u32) -> (f32, f32) { let ij = (p / (size), p % (size)); diff --git a/benches/benches/bevy_reflect/list.rs b/benches/benches/bevy_reflect/list.rs index dca727594f50a..872c2dd0cb898 100644 --- a/benches/benches/bevy_reflect/list.rs +++ b/benches/benches/bevy_reflect/list.rs @@ -1,10 +1,10 @@ -use core::{iter, time::Duration}; +use core::{hint::black_box, iter, time::Duration}; use benches::bench; use bevy_reflect::{DynamicList, List}; use criterion::{ - black_box, criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup, - BenchmarkId, Criterion, PlotConfiguration, Throughput, + criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup, BenchmarkId, + Criterion, PlotConfiguration, Throughput, }; criterion_group!( diff --git a/benches/benches/bevy_reflect/map.rs b/benches/benches/bevy_reflect/map.rs index f8f47feccb33c..d1d9d836039fc 100644 --- a/benches/benches/bevy_reflect/map.rs +++ b/benches/benches/bevy_reflect/map.rs @@ -1,11 +1,11 @@ -use core::{fmt::Write, iter, time::Duration}; +use core::{fmt::Write, hint::black_box, iter, time::Duration}; use benches::bench; use bevy_reflect::{DynamicMap, Map}; use bevy_utils::HashMap; use criterion::{ - black_box, criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup, - BenchmarkId, Criterion, PlotConfiguration, Throughput, + criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup, BenchmarkId, + Criterion, PlotConfiguration, Throughput, }; criterion_group!( diff --git a/benches/benches/bevy_reflect/path.rs b/benches/benches/bevy_reflect/path.rs index 9cf5d7250b261..c0d8bfe0da732 100644 --- a/benches/benches/bevy_reflect/path.rs +++ b/benches/benches/bevy_reflect/path.rs @@ -1,8 +1,8 @@ -use core::{fmt::Write, str, time::Duration}; +use core::{fmt::Write, hint::black_box, str, time::Duration}; use benches::bench; use bevy_reflect::ParsedPath; -use criterion::{black_box, criterion_group, BatchSize, BenchmarkId, Criterion, Throughput}; +use criterion::{criterion_group, BatchSize, BenchmarkId, Criterion, Throughput}; use rand::{distributions::Uniform, Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/benches/benches/bevy_reflect/struct.rs b/benches/benches/bevy_reflect/struct.rs index d71d006536fdf..d8f25554c36ba 100644 --- a/benches/benches/bevy_reflect/struct.rs +++ b/benches/benches/bevy_reflect/struct.rs @@ -1,10 +1,10 @@ -use core::time::Duration; +use core::{hint::black_box, time::Duration}; use benches::bench; use bevy_reflect::{DynamicStruct, GetField, PartialReflect, Reflect, Struct}; use criterion::{ - black_box, criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup, - BenchmarkId, Criterion, PlotConfiguration, Throughput, + criterion_group, measurement::Measurement, AxisScale, BatchSize, BenchmarkGroup, BenchmarkId, + Criterion, PlotConfiguration, Throughput, }; criterion_group!( diff --git a/benches/benches/bevy_render/render_layers.rs b/benches/benches/bevy_render/render_layers.rs index 42dd5356b55ed..d460a7bc96c48 100644 --- a/benches/benches/bevy_render/render_layers.rs +++ b/benches/benches/bevy_render/render_layers.rs @@ -1,4 +1,6 @@ -use criterion::{black_box, criterion_group, Criterion}; +use core::hint::black_box; + +use criterion::{criterion_group, Criterion}; use bevy_render::view::RenderLayers; diff --git a/benches/benches/bevy_render/torus.rs b/benches/benches/bevy_render/torus.rs index a5ef753bc8ccb..dcadd09180f9d 100644 --- a/benches/benches/bevy_render/torus.rs +++ b/benches/benches/bevy_render/torus.rs @@ -1,4 +1,6 @@ -use criterion::{black_box, criterion_group, Criterion}; +use core::hint::black_box; + +use criterion::{criterion_group, Criterion}; use bevy_render::mesh::TorusMeshBuilder; diff --git a/benches/benches/bevy_tasks/iter.rs b/benches/benches/bevy_tasks/iter.rs index 47c2f6de14902..7fe00ecb794db 100644 --- a/benches/benches/bevy_tasks/iter.rs +++ b/benches/benches/bevy_tasks/iter.rs @@ -1,5 +1,7 @@ +use core::hint::black_box; + use bevy_tasks::{ParallelIterator, TaskPoolBuilder}; -use criterion::{black_box, criterion_group, BenchmarkId, Criterion}; +use criterion::{criterion_group, BenchmarkId, Criterion}; struct ParChunks<'a, T>(core::slice::Chunks<'a, T>); impl<'a, T> ParallelIterator> for ParChunks<'a, T> diff --git a/clippy.toml b/clippy.toml index d1d234817a913..26b39b4e841e8 100644 --- a/clippy.toml +++ b/clippy.toml @@ -41,4 +41,5 @@ disallowed-methods = [ { path = "f32::asinh", reason = "use bevy_math::ops::asinh instead for libm determinism" }, { path = "f32::acosh", reason = "use bevy_math::ops::acosh instead for libm determinism" }, { path = "f32::atanh", reason = "use bevy_math::ops::atanh instead for libm determinism" }, + { path = "criterion::black_box", reason = "use core::hint::black_box instead" }, ] From 2dcf6bcfd74b2ed49a189b79eefc2f32eb6da90c Mon Sep 17 00:00:00 2001 From: super-saturn <127321359+super-saturn@users.noreply.github.com> Date: Sun, 29 Dec 2024 14:43:42 -0500 Subject: [PATCH 09/11] Fix path checking for FileWatcher for virtual workspace projects (#16958) # Objective Fixes #16879 ## Solution Moved the construction of the root path of the assets folder out of `FileWatcher::new()` and into `source.rs`, as the path is checked there with `path.exists()` and fails in certain configurations eg., virtual workspaces. ## Testing Applied fix to a private fork and tested against both standard project setups and virtual workspaces. Works without issue on both. Have tested under macOS and Arch Linux. --------- Co-authored-by: JP Stringham Co-authored-by: Alice Cecile --- crates/bevy_asset/src/io/file/file_watcher.rs | 6 +++--- crates/bevy_asset/src/io/source.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_asset/src/io/file/file_watcher.rs b/crates/bevy_asset/src/io/file/file_watcher.rs index a7024a4400898..0f10b493cd631 100644 --- a/crates/bevy_asset/src/io/file/file_watcher.rs +++ b/crates/bevy_asset/src/io/file/file_watcher.rs @@ -26,13 +26,13 @@ pub struct FileWatcher { impl FileWatcher { pub fn new( - root: PathBuf, + path: PathBuf, sender: Sender, debounce_wait_time: Duration, ) -> Result { - let root = normalize_path(super::get_base_path().join(root).as_path()); + let root = normalize_path(&path); let watcher = new_asset_event_debouncer( - root.clone(), + path.clone(), debounce_wait_time, FileEventHandler { root, diff --git a/crates/bevy_asset/src/io/source.rs b/crates/bevy_asset/src/io/source.rs index c0bab2037f8e3..f1b4455179710 100644 --- a/crates/bevy_asset/src/io/source.rs +++ b/crates/bevy_asset/src/io/source.rs @@ -531,7 +531,7 @@ impl AssetSource { not(target_os = "android") ))] { - let path = std::path::PathBuf::from(path.clone()); + let path = super::file::get_base_path().join(path.clone()); if path.exists() { Some(Box::new( super::file::FileWatcher::new( From dc2cd71dc81e8cb5750be196ddf0071908f53231 Mon Sep 17 00:00:00 2001 From: Brezak Date: Sun, 29 Dec 2024 20:54:57 +0100 Subject: [PATCH 10/11] Make `RawHandleWrapper` fields private to save users from themselves (#16968) # Objective Fixes #16683 ## Solution Make all fields ine `RawHandleWrapper` private. ## Testing - CI - `cargo clippy` - The lightmaps example --- ## Migration Guide The `window_handle` and `dispay_handle` fields on `RawHandleWrapper` are no longer public. Use the newly added getters and setters to manipulate them instead. --- crates/bevy_render/src/view/window/mod.rs | 4 +-- crates/bevy_window/src/raw_handle.rs | 39 +++++++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/crates/bevy_render/src/view/window/mod.rs b/crates/bevy_render/src/view/window/mod.rs index 14c0fe45befc7..c39090a2052dc 100644 --- a/crates/bevy_render/src/view/window/mod.rs +++ b/crates/bevy_render/src/view/window/mod.rs @@ -322,8 +322,8 @@ pub fn create_surfaces( .entry(window.entity) .or_insert_with(|| { let surface_target = SurfaceTargetUnsafe::RawHandle { - raw_display_handle: window.handle.display_handle, - raw_window_handle: window.handle.window_handle, + raw_display_handle: window.handle.get_display_handle(), + raw_window_handle: window.handle.get_window_handle(), }; // SAFETY: The window handles in ExtractedWindows will always be valid objects to create surfaces on let surface = unsafe { diff --git a/crates/bevy_window/src/raw_handle.rs b/crates/bevy_window/src/raw_handle.rs index 6084bc728f99e..d42ae6042456e 100644 --- a/crates/bevy_window/src/raw_handle.rs +++ b/crates/bevy_window/src/raw_handle.rs @@ -49,9 +49,9 @@ impl Deref for WindowWrapper { pub struct RawHandleWrapper { _window: Arc, /// Raw handle to a window. - pub window_handle: RawWindowHandle, + window_handle: RawWindowHandle, /// Raw handle to the display server. - pub display_handle: RawDisplayHandle, + display_handle: RawDisplayHandle, } impl RawHandleWrapper { @@ -75,6 +75,41 @@ impl RawHandleWrapper { pub unsafe fn get_handle(&self) -> ThreadLockedRawWindowHandleWrapper { ThreadLockedRawWindowHandleWrapper(self.clone()) } + + /// Gets the stored window handle. + pub fn get_window_handle(&self) -> RawWindowHandle { + self.window_handle + } + + /// Sets the window handle. + /// + /// # Safety + /// + /// The passed in [`RawWindowHandle`] must be a valid window handle. + // NOTE: The use of an explicit setter instead of a getter for a mutable reference is to limit the amount of time unsoundness can happen. + // If we handed out a mutable reference the user would have to maintain safety invariants throughout its lifetime. For consistency + // we also prefer to handout copies of the handles instead of immutable references. + pub unsafe fn set_window_handle(&mut self, window_handle: RawWindowHandle) -> &mut Self { + self.window_handle = window_handle; + + self + } + + /// Gets the stored display handle + pub fn get_display_handle(&self) -> RawDisplayHandle { + self.display_handle + } + + /// Sets the display handle. + /// + /// # Safety + /// + /// The passed in [`RawDisplayHandle`] must be a valid display handle. + pub fn set_display_handle(&mut self, display_handle: RawDisplayHandle) -> &mut Self { + self.display_handle = display_handle; + + self + } } // SAFETY: [`RawHandleWrapper`] is just a normal "raw pointer", which doesn't impl Send/Sync. However the pointer is only From 8c34f00deb20e23902060ad486631828e5ed1bb6 Mon Sep 17 00:00:00 2001 From: Benjamin Brienen Date: Sun, 29 Dec 2024 15:00:19 -0500 Subject: [PATCH 11/11] Fix msrvs (#17012) # Objective The rust-versions are out of date. Fixes #17008 ## Solution Update the values Cherry-picked from #17006 in case it is controversial ## Testing Validated locally and in #17006 --------- Co-authored-by: Alice Cecile --- crates/bevy_color/Cargo.toml | 2 +- crates/bevy_ecs/Cargo.toml | 2 +- crates/bevy_input_focus/Cargo.toml | 2 +- crates/bevy_math/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_color/Cargo.toml b/crates/bevy_color/Cargo.toml index cb53472950161..ec71e3960d18a 100644 --- a/crates/bevy_color/Cargo.toml +++ b/crates/bevy_color/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://bevyengine.org" repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy", "color"] -rust-version = "1.82.0" +rust-version = "1.83.0" [dependencies] bevy_math = { path = "../bevy_math", version = "0.15.0-dev", default-features = false, features = [ diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index e32b51a916637..061fa265b6d44 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["ecs", "game", "bevy"] categories = ["game-engines", "data-structures"] -rust-version = "1.82.0" +rust-version = "1.83.0" [features] default = ["std", "bevy_reflect", "async_executor"] diff --git a/crates/bevy_input_focus/Cargo.toml b/crates/bevy_input_focus/Cargo.toml index eb5420225fc5a..75c85845b1837 100644 --- a/crates/bevy_input_focus/Cargo.toml +++ b/crates/bevy_input_focus/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://bevyengine.org" repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy"] -rust-version = "1.76.0" +rust-version = "1.83.0" [dependencies] bevy_app = { path = "../bevy_app", version = "0.15.0-dev", default-features = false } diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index c444004521606..7510f6df926f3 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://bevyengine.org" repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy"] -rust-version = "1.81.0" +rust-version = "1.83.0" [dependencies] glam = { version = "0.29", default-features = false, features = ["bytemuck"] }