From 8734b668e314dde2906af76c93178895c74937ff Mon Sep 17 00:00:00 2001 From: Zachary Harrold Date: Mon, 30 Dec 2024 09:46:30 +1100 Subject: [PATCH] Add `no_std` support to `bevy_input` (#16995) # Objective - Contributes to #15460 ## Solution - Added the following features: - `std` (default) - `smol_str` (default) - `portable-atomic` - `critical-section` - `libm` - Fixed an existing issue where `bevy_reflect` wasn't properly feature gated. ## Testing - CI ## Notes - There were some minor issues with `bevy_math` and `bevy_ecs` noticed in this PR which I have also resolved here. I can split these out if desired, but I've left them here for now as they're very small changes and I don't consider this PR itself to be very controversial. - `libm`, `portable-atomic`, and `critical-section` are shortcuts to enable the relevant features in dependencies, making the usage of this crate on atomically challenged platforms possible and simpler. - `smol_str` is gated as it doesn't support atomically challenged platforms (e.g., Raspberry Pi Pico). I have an issue and a [PR](https://github.com/rust-analyzer/smol_str/pull/91) to discuss this upstream. --- crates/bevy_ecs/src/name.rs | 9 ++- crates/bevy_input/Cargo.toml | 64 +++++++++++++---- crates/bevy_input/src/gamepad.rs | 68 +++++++++---------- crates/bevy_input/src/keyboard.rs | 6 ++ crates/bevy_input/src/lib.rs | 3 + crates/bevy_math/Cargo.toml | 7 +- tools/ci/src/commands/compile_check_no_std.rs | 8 +++ 7 files changed, 111 insertions(+), 54 deletions(-) diff --git a/crates/bevy_ecs/src/name.rs b/crates/bevy_ecs/src/name.rs index 3ae68798a17bf..4697bb50e9435 100644 --- a/crates/bevy_ecs/src/name.rs +++ b/crates/bevy_ecs/src/name.rs @@ -13,9 +13,12 @@ use core::{ }; #[cfg(feature = "serialize")] -use serde::{ - de::{Error, Visitor}, - Deserialize, Deserializer, Serialize, Serializer, +use { + alloc::string::ToString, + serde::{ + de::{Error, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, + }, }; #[cfg(feature = "bevy_reflect")] diff --git a/crates/bevy_input/Cargo.toml b/crates/bevy_input/Cargo.toml index fa185ea5feed9..c5b976c73b2b0 100644 --- a/crates/bevy_input/Cargo.toml +++ b/crates/bevy_input/Cargo.toml @@ -9,36 +9,72 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -default = ["bevy_reflect"] +default = ["std", "bevy_reflect", "bevy_ecs/async_executor", "smol_str"] + +# Functionality + +## Adds runtime reflection support using `bevy_reflect`. bevy_reflect = [ "dep:bevy_reflect", "bevy_app/bevy_reflect", "bevy_ecs/bevy_reflect", "bevy_math/bevy_reflect", ] -serialize = ["serde", "smol_str/serde"] + +## Adds serialization support through `serde`. +serialize = [ + "serde", + "smol_str/serde", + "bevy_ecs/serialize", + "bevy_math/serialize", +] + +## Uses the small-string optimization provided by `smol_str`. +smol_str = ["dep:smol_str", "bevy_reflect/smol_str"] + +# 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_math/std", + "bevy_utils/std", + "bevy_reflect/std", +] + +## `critical-section` provides the building blocks for synchronization primitives +## on all platforms, including `no_std`. +critical-section = ["bevy_app/critical-section", "bevy_ecs/critical-section"] + +## `portable-atomic` provides additional platform support for atomic types and +## operations, even on targets without native support. +portable-atomic = ["bevy_app/portable-atomic", "bevy_ecs/portable-atomic"] + +## Uses the `libm` maths library instead of the one provided in `std` and `core`. +libm = ["bevy_math/libm"] [dependencies] # bevy bevy_app = { path = "../bevy_app", version = "0.15.0-dev", default-features = false } -bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false, features = [ - "serialize", -] } -bevy_math = { path = "../bevy_math", version = "0.15.0-dev", default-features = false, features = [ - "rand", - "serialize", -] } -bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false } +bevy_math = { path = "../bevy_math", version = "0.15.0-dev", default-features = false } +bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev", default-features = false } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [ "glam", - "smol_str", -], optional = true } +], default-features = false, optional = true } # other -serde = { version = "1", features = ["derive"], optional = true } +serde = { version = "1", features = [ + "alloc", + "derive", +], default-features = false, optional = true } thiserror = { version = "2", default-features = false } derive_more = { version = "1", default-features = false, features = ["from"] } -smol_str = "0.2" +smol_str = { version = "0.2", default-features = false, optional = true } +log = { version = "0.4", default-features = false } [lints] workspace = true diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 92f1149a2a77e..6762627e14f5f 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,6 +1,7 @@ //! The gamepad input functionality. use crate::{Axis, ButtonInput, ButtonState}; +use alloc::string::String; #[cfg(feature = "bevy_reflect")] use bevy_ecs::prelude::ReflectComponent; use bevy_ecs::{ @@ -12,16 +13,15 @@ use bevy_ecs::{ prelude::require, system::{Commands, Query}, }; +use bevy_math::ops; use bevy_math::Vec2; #[cfg(feature = "bevy_reflect")] use bevy_reflect::{std_traits::ReflectDefault, Reflect}; #[cfg(all(feature = "serialize", feature = "bevy_reflect"))] use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; -use bevy_utils::{ - tracing::{info, warn}, - Duration, HashMap, -}; +use bevy_utils::{Duration, HashMap}; use derive_more::derive::From; +use log::{info, warn}; use thiserror::Error; /// A gamepad event. @@ -54,11 +54,11 @@ pub enum GamepadEvent { /// the in-frame relative ordering of events is important. /// /// This event type is used by `bevy_input` to feed its components. -#[derive(Event, Debug, Clone, PartialEq, Reflect, From)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Clone, PartialEq, From)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] pub enum RawGamepadEvent { @@ -71,11 +71,11 @@ pub enum RawGamepadEvent { } /// [`GamepadButton`] changed event unfiltered by [`GamepadSettings`] -#[derive(Event, Debug, Copy, Clone, PartialEq, Reflect)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] pub struct RawGamepadButtonChangedEvent { @@ -99,11 +99,11 @@ impl RawGamepadButtonChangedEvent { } /// [`GamepadAxis`] changed event unfiltered by [`GamepadSettings`] -#[derive(Event, Debug, Copy, Clone, PartialEq, Reflect)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] pub struct RawGamepadAxisChangedEvent { @@ -128,11 +128,11 @@ impl RawGamepadAxisChangedEvent { /// A Gamepad connection event. Created when a connection to a gamepad /// is established and when a gamepad is disconnected. -#[derive(Event, Debug, Clone, PartialEq, Reflect)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Clone, PartialEq)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] pub struct GamepadConnectionEvent { @@ -163,11 +163,11 @@ impl GamepadConnectionEvent { } /// [`GamepadButton`] event triggered by a digital state change -#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] pub struct GamepadButtonStateChangedEvent { @@ -191,11 +191,11 @@ impl GamepadButtonStateChangedEvent { } /// [`GamepadButton`] event triggered by an analog state change -#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] pub struct GamepadButtonChangedEvent { @@ -222,11 +222,11 @@ impl GamepadButtonChangedEvent { } /// [`GamepadAxis`] event triggered by an analog state change -#[derive(Event, Debug, Clone, Copy, PartialEq, Reflect)] -#[reflect(Debug, PartialEq)] +#[derive(Event, Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] #[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), + all(feature = "bevy_reflect", feature = "serialize"), reflect(Serialize, Deserialize) )] pub struct GamepadAxisChangedEvent { @@ -1232,7 +1232,7 @@ impl AxisSettings { return true; } - f32::abs(new_value - old_value.unwrap()) > self.threshold + ops::abs(new_value - old_value.unwrap()) > self.threshold } /// Filters the `new_value` based on the `old_value`, according to the [`AxisSettings`]. @@ -1307,7 +1307,7 @@ impl ButtonAxisSettings { return true; } - f32::abs(new_value - old_value.unwrap()) > self.threshold + ops::abs(new_value - old_value.unwrap()) > self.threshold } /// Filters the `new_value` based on the `old_value`, according to the [`ButtonAxisSettings`]. diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 0bd6f41a84750..6ce72ef801f06 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -72,8 +72,14 @@ use bevy_ecs::{ event::{Event, EventReader}, system::ResMut, }; + #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; + +#[cfg(not(feature = "smol_str"))] +use alloc::string::String as SmolStr; + +#[cfg(feature = "smol_str")] use smol_str::SmolStr; #[cfg(all(feature = "serialize", feature = "bevy_reflect"))] diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 7e0225cf7521c..5826d174f4a23 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/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)] //! Input functionality for the [Bevy game engine](https://bevyengine.org/). //! @@ -11,6 +12,8 @@ //! //! `bevy` currently supports keyboard, mouse, gamepad, and touch inputs. +extern crate alloc; + mod axis; mod button_input; /// Common run conditions diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index 7510f6df926f3..c0fd55748ae3f 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -25,7 +25,7 @@ approx = { version = "0.5", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } rand_distr = { version = "0.4.3", optional = true } smallvec = { version = "1.11" } -bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [ +bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", default-features = false, features = [ "glam", ], optional = true } variadics_please = "1.1" @@ -52,6 +52,7 @@ std = [ "approx?/std", "rand?/std", "rand_distr?/std", + "bevy_reflect?/std", ] alloc = [ "itertools/use_alloc", @@ -76,8 +77,8 @@ debug_glam_assert = ["glam/debug-glam-assert"] rand = ["dep:rand", "dep:rand_distr", "glam/rand"] # Include code related to the Curve trait curve = [] -# Enable bevy_reflect (requires std) -bevy_reflect = ["dep:bevy_reflect", "std"] +# Enable bevy_reflect (requires alloc) +bevy_reflect = ["dep:bevy_reflect", "alloc"] [lints] workspace = true diff --git a/tools/ci/src/commands/compile_check_no_std.rs b/tools/ci/src/commands/compile_check_no_std.rs index 946bed361af6c..073daacb47a22 100644 --- a/tools/ci/src/commands/compile_check_no_std.rs +++ b/tools/ci/src/commands/compile_check_no_std.rs @@ -118,6 +118,14 @@ impl Prepare for CompileCheckNoStdCommand { "Please fix compiler errors in output above for bevy_hierarchy no_std compatibility.", )); + commands.push(PreparedCommand::new::( + cmd!( + sh, + "cargo check -p bevy_input --no-default-features --features libm,serialize,bevy_reflect --target {target}" + ), + "Please fix compiler errors in output above for bevy_input no_std compatibility.", + )); + commands } }