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,
|
Deserialize,
|
||||||
Default
|
Default
|
||||||
));
|
));
|
||||||
#[cfg(any(target_arch = "wasm32", feature = "std"))]
|
|
||||||
impl_reflect_opaque!(::bevy_platform_support::time::Instant(
|
impl_reflect_opaque!(::bevy_platform_support::time::Instant(
|
||||||
Debug, Hash, PartialEq
|
Debug, Hash, PartialEq
|
||||||
));
|
));
|
||||||
|
@ -9,26 +9,69 @@ license = "MIT OR Apache-2.0"
|
|||||||
keywords = ["bevy"]
|
keywords = ["bevy"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["bevy_reflect"]
|
default = ["std", "bevy_reflect", "bevy_app/default"]
|
||||||
serialize = ["serde"]
|
|
||||||
|
# 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]
|
[dependencies]
|
||||||
# bevy
|
# bevy
|
||||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
|
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false }
|
||||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", features = [
|
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
|
||||||
"bevy_reflect",
|
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
|
||||||
] }
|
|
||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
|
||||||
"bevy",
|
"bevy",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [
|
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false }
|
||||||
"std",
|
|
||||||
] }
|
|
||||||
|
|
||||||
# other
|
# other
|
||||||
crossbeam-channel = "0.5.0"
|
crossbeam-channel = { version = "0.5.0", default-features = false, features = [
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
"std",
|
||||||
tracing = { version = "0.1", 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]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||||
html_favicon_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
|
/// Common run conditions
|
||||||
pub mod common_conditions;
|
pub mod common_conditions;
|
||||||
@ -37,9 +43,12 @@ use bevy_ecs::{
|
|||||||
};
|
};
|
||||||
use bevy_platform_support::time::Instant;
|
use bevy_platform_support::time::Instant;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub use crossbeam_channel::TrySendError;
|
pub use crossbeam_channel::TrySendError;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
/// Adds time functionality to Apps.
|
/// Adds time functionality to Apps.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -92,8 +101,9 @@ impl Plugin for TimePlugin {
|
|||||||
/// networking or similar, you may prefer to set the next [`Time`] value manually.
|
/// networking or similar, you may prefer to set the next [`Time`] value manually.
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub enum TimeUpdateStrategy {
|
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.
|
/// If nothing is sent, the system clock will be used instead.
|
||||||
|
#[cfg_attr(feature = "std", doc = "See [`TimeSender`] for more details.")]
|
||||||
#[default]
|
#[default]
|
||||||
Automatic,
|
Automatic,
|
||||||
/// [`Time`] will be updated to the specified [`Instant`] value each frame.
|
/// [`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.
|
/// Channel resource used to receive time from the render world.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct TimeReceiver(pub Receiver<Instant>);
|
pub struct TimeReceiver(pub Receiver<Instant>);
|
||||||
|
|
||||||
/// Channel resource used to send time from the render world.
|
/// Channel resource used to send time from the render world.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct TimeSender(pub Sender<Instant>);
|
pub struct TimeSender(pub Sender<Instant>);
|
||||||
|
|
||||||
/// Creates channels used for sending time between the render world and the main world.
|
/// Creates channels used for sending time between the render world and the main world.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub fn create_time_channels() -> (TimeSender, TimeReceiver) {
|
pub fn create_time_channels() -> (TimeSender, TimeReceiver) {
|
||||||
// bound the channel to 2 since when pipelined the render phase can finish before
|
// bound the channel to 2 since when pipelined the render phase can finish before
|
||||||
// the time system runs.
|
// the time system runs.
|
||||||
@ -128,26 +141,32 @@ pub fn time_system(
|
|||||||
mut virtual_time: ResMut<Time<Virtual>>,
|
mut virtual_time: ResMut<Time<Virtual>>,
|
||||||
mut time: ResMut<Time>,
|
mut time: ResMut<Time>,
|
||||||
update_strategy: Res<TimeUpdateStrategy>,
|
update_strategy: Res<TimeUpdateStrategy>,
|
||||||
time_recv: Option<Res<TimeReceiver>>,
|
#[cfg(feature = "std")] time_recv: Option<Res<TimeReceiver>>,
|
||||||
mut has_received_time: Local<bool>,
|
#[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() {
|
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::ManualInstant(instant) => real_time.update_with_instant(*instant),
|
||||||
TimeUpdateStrategy::ManualDuration(duration) => real_time.update_with_duration(*duration),
|
TimeUpdateStrategy::ManualDuration(duration) => real_time.update_with_duration(*duration),
|
||||||
}
|
}
|
||||||
@ -166,6 +185,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use core::error::Error;
|
use core::error::Error;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
use std::println;
|
||||||
|
|
||||||
#[derive(Event)]
|
#[derive(Event)]
|
||||||
struct TestEvent<T: Default> {
|
struct TestEvent<T: Default> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use tracing::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::{real::Real, time::Time};
|
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.",
|
"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>(
|
commands.push(PreparedCommand::new::<Self>(
|
||||||
cmd!(
|
cmd!(
|
||||||
sh,
|
sh,
|
||||||
|
Loading…
Reference in New Issue
Block a user