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 <alice.i.cecile@gmail.com>
This commit is contained in:
parent
f32a6fb205
commit
d921fdc376
@ -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
|
||||
));
|
||||
|
@ -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
|
||||
|
@ -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<Instant>);
|
||||
|
||||
/// Channel resource used to send time from the render world.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Resource)]
|
||||
pub struct TimeSender(pub Sender<Instant>);
|
||||
|
||||
/// 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<Time<Virtual>>,
|
||||
mut time: ResMut<Time>,
|
||||
update_strategy: Res<TimeUpdateStrategy>,
|
||||
time_recv: Option<Res<TimeReceiver>>,
|
||||
mut has_received_time: Local<bool>,
|
||||
#[cfg(feature = "std")] time_recv: Option<Res<TimeReceiver>>,
|
||||
#[cfg(feature = "std")] mut has_received_time: Local<bool>,
|
||||
) {
|
||||
let new_time = if let Some(time_recv) = time_recv {
|
||||
// TODO: Figure out how to handle this when using pipelined rendering.
|
||||
if let Ok(new_time) = time_recv.0.try_recv() {
|
||||
*has_received_time = true;
|
||||
new_time
|
||||
} else {
|
||||
if *has_received_time {
|
||||
warn!("time_system did not receive the time from the render world! Calculations depending on the time may be incorrect.");
|
||||
}
|
||||
Instant::now()
|
||||
}
|
||||
} else {
|
||||
Instant::now()
|
||||
};
|
||||
|
||||
match update_strategy.as_ref() {
|
||||
TimeUpdateStrategy::Automatic => real_time.update_with_instant(new_time),
|
||||
TimeUpdateStrategy::Automatic => {
|
||||
#[cfg(feature = "std")]
|
||||
let new_time = if let Some(time_recv) = time_recv {
|
||||
// TODO: Figure out how to handle this when using pipelined rendering.
|
||||
if let Ok(new_time) = time_recv.0.try_recv() {
|
||||
*has_received_time = true;
|
||||
new_time
|
||||
} else {
|
||||
if *has_received_time {
|
||||
log::warn!("time_system did not receive the time from the render world! Calculations depending on the time may be incorrect.");
|
||||
}
|
||||
Instant::now()
|
||||
}
|
||||
} else {
|
||||
Instant::now()
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
let new_time = Instant::now();
|
||||
|
||||
real_time.update_with_instant(new_time);
|
||||
}
|
||||
TimeUpdateStrategy::ManualInstant(instant) => real_time.update_with_instant(*instant),
|
||||
TimeUpdateStrategy::ManualDuration(duration) => real_time.update_with_duration(*duration),
|
||||
}
|
||||
@ -166,6 +185,7 @@ mod tests {
|
||||
};
|
||||
use core::error::Error;
|
||||
use core::time::Duration;
|
||||
use std::println;
|
||||
|
||||
#[derive(Event)]
|
||||
struct TestEvent<T: Default> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::Reflect;
|
||||
use core::time::Duration;
|
||||
use tracing::debug;
|
||||
use log::debug;
|
||||
|
||||
use crate::{real::Real, time::Time};
|
||||
|
||||
|
@ -142,6 +142,14 @@ impl Prepare for CompileCheckNoStdCommand {
|
||||
"Please fix compiler errors in output above for bevy_transform no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_time --no-default-features --features bevy_reflect,serialize --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_transform no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
|
Loading…
Reference in New Issue
Block a user