From d921fdc376998a805c6e73df1f42e7644eab9f9b Mon Sep 17 00:00:00 2001 From: Zachary Harrold Date: Thu, 23 Jan 2025 07:02:43 +1100 Subject: [PATCH] Add `no_std` Support to `bevy_time` (#17491) # Objective - Contributes to #15460 ## Solution - Switched `tracing` for `log` for the atomically challenged platforms - Setup feature flags as required - Added to `compile-check-no-std` CI task - Made `crossbeam-channel` optional depending on `std`. ## Testing - CI --- ## Notes - `crossbeam-channel` provides a MPMC channel type which isn't readily replicable in `no_std`, and is only used for a `bevy_render` integration. As such, I've feature-gated the `TimeReceiver` and `TimeSender` types. --------- Co-authored-by: Alice Cecile --- crates/bevy_reflect/src/impls/std.rs | 1 - crates/bevy_time/Cargo.toml | 69 +++++++++++++++---- crates/bevy_time/src/lib.rs | 60 ++++++++++------ crates/bevy_time/src/virt.rs | 2 +- tools/ci/src/commands/compile_check_no_std.rs | 8 +++ 5 files changed, 105 insertions(+), 35 deletions(-) diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 1e80e278045b0..6155321540ef0 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -126,7 +126,6 @@ impl_reflect_opaque!(::core::time::Duration( Deserialize, Default )); -#[cfg(any(target_arch = "wasm32", feature = "std"))] impl_reflect_opaque!(::bevy_platform_support::time::Instant( Debug, Hash, PartialEq )); diff --git a/crates/bevy_time/Cargo.toml b/crates/bevy_time/Cargo.toml index 257f7da8e51e8..b0db99b6588fa 100644 --- a/crates/bevy_time/Cargo.toml +++ b/crates/bevy_time/Cargo.toml @@ -9,26 +9,69 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -default = ["bevy_reflect"] -serialize = ["serde"] +default = ["std", "bevy_reflect", "bevy_app/default"] + +# Functionality + +## Adds runtime reflection support using `bevy_reflect`. +bevy_reflect = [ + "dep:bevy_reflect", + "bevy_ecs/bevy_reflect", + "bevy_app/bevy_reflect", +] + +## Adds serialization support through `serde`. +serialize = ["dep:serde", "bevy_ecs/serialize"] + +# 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 = [ + "serde?/std", + "bevy_reflect?/std", + "bevy_ecs/std", + "bevy_app/std", + "bevy_platform_support/std", + "dep:crossbeam-channel", +] + +## `critical-section` provides the building blocks for synchronization primitives +## on all platforms, including `no_std`. +critical-section = [ + "bevy_ecs/critical-section", + "bevy_platform_support/critical-section", + "bevy_reflect?/critical-section", + "bevy_app/critical-section", +] + +## `portable-atomic` provides additional platform support for atomic types and +## operations, even on targets without native support. +portable-atomic = [ + "bevy_ecs/portable-atomic", + "bevy_platform_support/portable-atomic", + "bevy_reflect?/portable-atomic", + "bevy_app/portable-atomic", +] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.16.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", features = [ - "bevy_reflect", -] } -bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [ +bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false } +bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false } +bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [ "bevy", ], optional = true } -bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [ - "std", -] } +bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false } # other -crossbeam-channel = "0.5.0" -serde = { version = "1", features = ["derive"], optional = true } -tracing = { version = "0.1", default-features = false, features = ["std"] } +crossbeam-channel = { version = "0.5.0", default-features = false, features = [ + "std", +], optional = true } +serde = { version = "1", features = [ + "derive", +], default-features = false, optional = true } +log = { version = "0.4", default-features = false } [lints] workspace = true diff --git a/crates/bevy_time/src/lib.rs b/crates/bevy_time/src/lib.rs index cb85872672678..d50302b5600d5 100644 --- a/crates/bevy_time/src/lib.rs +++ b/crates/bevy_time/src/lib.rs @@ -5,6 +5,12 @@ html_logo_url = "https://bevyengine.org/assets/icon.png", html_favicon_url = "https://bevyengine.org/assets/icon.png" )] +#![no_std] + +#[cfg(feature = "std")] +extern crate std; + +extern crate alloc; /// Common run conditions pub mod common_conditions; @@ -37,9 +43,12 @@ use bevy_ecs::{ }; use bevy_platform_support::time::Instant; use core::time::Duration; + +#[cfg(feature = "std")] pub use crossbeam_channel::TrySendError; + +#[cfg(feature = "std")] use crossbeam_channel::{Receiver, Sender}; -use tracing::warn; /// Adds time functionality to Apps. #[derive(Default)] @@ -92,8 +101,9 @@ impl Plugin for TimePlugin { /// networking or similar, you may prefer to set the next [`Time`] value manually. #[derive(Resource, Default)] pub enum TimeUpdateStrategy { - /// [`Time`] will be automatically updated each frame using an [`Instant`] sent from the render world via a [`TimeSender`]. + /// [`Time`] will be automatically updated each frame using an [`Instant`] sent from the render world. /// If nothing is sent, the system clock will be used instead. + #[cfg_attr(feature = "std", doc = "See [`TimeSender`] for more details.")] #[default] Automatic, /// [`Time`] will be updated to the specified [`Instant`] value each frame. @@ -106,14 +116,17 @@ pub enum TimeUpdateStrategy { } /// Channel resource used to receive time from the render world. +#[cfg(feature = "std")] #[derive(Resource)] pub struct TimeReceiver(pub Receiver); /// Channel resource used to send time from the render world. +#[cfg(feature = "std")] #[derive(Resource)] pub struct TimeSender(pub Sender); /// Creates channels used for sending time between the render world and the main world. +#[cfg(feature = "std")] pub fn create_time_channels() -> (TimeSender, TimeReceiver) { // bound the channel to 2 since when pipelined the render phase can finish before // the time system runs. @@ -128,26 +141,32 @@ pub fn time_system( mut virtual_time: ResMut>, mut time: ResMut