Add no_std
support to bevy
(#17955)
# Objective - Fixes #15460 (will open new issues for further `no_std` efforts) - Supersedes #17715 ## Solution - Threaded in new features as required - Made certain crates optional but default enabled - Removed `compile-check-no-std` from internal `ci` tool since GitHub CI can now simply check `bevy` itself now - Added CI task to check `bevy` on `thumbv6m-none-eabi` to ensure `portable-atomic` support is still valid [^1] [^1]: This may be controversial, since it could be interpreted as implying Bevy will maintain support for `thumbv6m-none-eabi` going forward. In reality, just like `x86_64-unknown-none`, this is a [canary](https://en.wiktionary.org/wiki/canary_in_a_coal_mine) target to make it clear when `portable-atomic` no longer works as intended (fixing atomic support on atomically challenged platforms). If a PR comes through and makes supporting this class of platforms impossible, then this CI task can be removed. I however wager this won't be a problem. ## Testing - CI --- ## Release Notes Bevy now has support for `no_std` directly from the `bevy` crate. Users can disable default features and enable a new `default_no_std` feature instead, allowing `bevy` to be used in `no_std` applications and libraries. ```toml # Bevy for `no_std` platforms bevy = { version = "0.16", default-features = false, features = ["default_no_std"] } ``` `default_no_std` enables certain required features, such as `libm` and `critical-section`, and as many optional crates as possible (currently just `bevy_state`). For atomically-challenged platforms such as the Raspberry Pi Pico, `portable-atomic` will be used automatically. For library authors, we recommend depending on `bevy` with `default-features = false` to allow `std` and `no_std` users to both depend on your crate. Here are some recommended features a library crate may want to expose: ```toml [features] # Most users will be on a platform which has `std` and can use the more-powerful `async_executor`. default = ["std", "async_executor"] # Features for typical platforms. std = ["bevy/std"] async_executor = ["bevy/async_executor"] # Features for `no_std` platforms. libm = ["bevy/libm"] critical-section = ["bevy/critical-section"] [dependencies] # We disable default features to ensure we don't accidentally enable `std` on `no_std` targets, for example. bevy = { version = "0.16", default-features = false } ``` While this is verbose, it gives the maximum control to end-users to decide how they wish to use Bevy on their platform. We encourage library authors to experiment with `no_std` support. For libraries relying exclusively on `bevy` and no other dependencies, it may be as simple as adding `#![no_std]` to your `lib.rs` and exposing features as above! Bevy can also provide many `std` types, such as `HashMap`, `Mutex`, and `Instant` on all platforms. See `bevy::platform_support` for details on what's available out of the box! ## Migration Guide - If you were previously relying on `bevy` with default features disabled, you may need to enable the `std` and `async_executor` features. - `bevy_reflect` has had its `bevy` feature removed. If you were relying on this feature, simply enable `smallvec` and `smol_str` instead. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
5bc1d68a65
commit
cc69fdd0c6
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
@ -151,7 +151,31 @@ jobs:
|
||||
- name: Install Linux dependencies
|
||||
uses: ./.github/actions/install-linux-deps
|
||||
- name: Check Compile
|
||||
run: cargo run -p ci -- compile-check-no-std
|
||||
run: cargo check -p bevy --no-default-features --features default_no_std --target x86_64-unknown-none
|
||||
check-compiles-no-std-portable-atomic:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: ci
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
crates/bevy_ecs_compile_fail_tests/target/
|
||||
crates/bevy_reflect_compile_fail_tests/target/
|
||||
key: ${{ runner.os }}-cargo-check-compiles-no-std-portable-atomic-${{ hashFiles('**/Cargo.toml') }}
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: thumbv6m-none-eabi
|
||||
- name: Install Linux dependencies
|
||||
uses: ./.github/actions/install-linux-deps
|
||||
- name: Check Compile
|
||||
run: cargo check -p bevy --no-default-features --features default_no_std --target thumbv6m-none-eabi
|
||||
|
||||
build-wasm:
|
||||
runs-on: ubuntu-latest
|
||||
|
25
Cargo.toml
25
Cargo.toml
@ -120,6 +120,8 @@ unused_qualifications = "warn"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"std",
|
||||
"async_executor",
|
||||
"android-game-activity",
|
||||
"android_shared_stdcxx",
|
||||
"animation",
|
||||
@ -130,6 +132,8 @@ default = [
|
||||
"bevy_gilrs",
|
||||
"bevy_gizmos",
|
||||
"bevy_gltf",
|
||||
"bevy_input_focus",
|
||||
"bevy_log",
|
||||
"bevy_mesh_picking_backend",
|
||||
"bevy_pbr",
|
||||
"bevy_picking",
|
||||
@ -156,6 +160,9 @@ default = [
|
||||
"x11",
|
||||
]
|
||||
|
||||
# Recommended defaults for no_std applications
|
||||
default_no_std = ["libm", "critical-section", "bevy_color", "bevy_state"]
|
||||
|
||||
# Provides an implementation for picking meshes
|
||||
bevy_mesh_picking_backend = [
|
||||
"bevy_picking",
|
||||
@ -263,6 +270,12 @@ bevy_dev_tools = ["bevy_internal/bevy_dev_tools"]
|
||||
# Enable the Bevy Remote Protocol
|
||||
bevy_remote = ["bevy_internal/bevy_remote"]
|
||||
|
||||
# Enable integration with `tracing` and `log`
|
||||
bevy_log = ["bevy_internal/bevy_log"]
|
||||
|
||||
# Enable input focus subsystem
|
||||
bevy_input_focus = ["bevy_internal/bevy_input_focus"]
|
||||
|
||||
# Enable passthrough loading for SPIR-V shaders (Only supported on Vulkan, shader capabilities and extensions must agree with the platform implementation)
|
||||
spirv_shader_passthrough = ["bevy_internal/spirv_shader_passthrough"]
|
||||
|
||||
@ -488,6 +501,18 @@ custom_cursor = ["bevy_internal/custom_cursor"]
|
||||
# Experimental support for nodes that are ignored for UI layouting
|
||||
ghost_nodes = ["bevy_internal/ghost_nodes"]
|
||||
|
||||
# Uses `async-executor` as a task execution backend.
|
||||
async_executor = ["std", "bevy_internal/async_executor"]
|
||||
|
||||
# Allows access to the `std` crate.
|
||||
std = ["bevy_internal/std"]
|
||||
|
||||
# `critical-section` provides the building blocks for synchronization primitives on all platforms, including `no_std`.
|
||||
critical-section = ["bevy_internal/critical-section"]
|
||||
|
||||
# Uses the `libm` maths library instead of the one provided in `std` and `core`.
|
||||
libm = ["bevy_internal/libm"]
|
||||
|
||||
[dependencies]
|
||||
bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false, optional = true }
|
||||
|
@ -17,7 +17,6 @@ bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
"petgraph",
|
||||
] }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
|
||||
|
@ -9,13 +9,7 @@ license = "MIT OR Apache-2.0"
|
||||
keywords = ["bevy"]
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"std",
|
||||
"bevy_reflect",
|
||||
"bevy_tasks",
|
||||
"bevy_ecs/default",
|
||||
"error_panic_hook",
|
||||
]
|
||||
default = ["std", "bevy_reflect", "bevy_ecs/default", "error_panic_hook"]
|
||||
|
||||
# Functionality
|
||||
|
||||
@ -29,9 +23,6 @@ reflect_functions = [
|
||||
"bevy_ecs/reflect_functions",
|
||||
]
|
||||
|
||||
## Adds support for running async background tasks
|
||||
bevy_tasks = ["dep:bevy_tasks"]
|
||||
|
||||
# Debugging Features
|
||||
|
||||
## Enables `tracing` integration, allowing spans and other metrics to be reported
|
||||
@ -57,14 +48,14 @@ std = [
|
||||
"dep:ctrlc",
|
||||
"downcast-rs/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_tasks?/std",
|
||||
"bevy_tasks/std",
|
||||
"bevy_platform_support/std",
|
||||
]
|
||||
|
||||
## `critical-section` provides the building blocks for synchronization primitives
|
||||
## on all platforms, including `no_std`.
|
||||
critical-section = [
|
||||
"bevy_tasks?/critical-section",
|
||||
"bevy_tasks/critical-section",
|
||||
"bevy_ecs/critical-section",
|
||||
"bevy_platform_support/critical-section",
|
||||
"bevy_reflect?/critical-section",
|
||||
@ -78,7 +69,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-featu
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false }
|
||||
|
||||
# other
|
||||
|
@ -1353,7 +1353,7 @@ type RunnerFn = Box<dyn FnOnce(App) -> AppExit>;
|
||||
|
||||
fn run_once(mut app: App) -> AppExit {
|
||||
while app.plugins_state() == PluginsState::Adding {
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "bevy_tasks"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
bevy_tasks::tick_global_task_pools_on_main_thread();
|
||||
}
|
||||
app.finish();
|
||||
|
@ -30,7 +30,6 @@ mod plugin;
|
||||
mod plugin_group;
|
||||
mod schedule_runner;
|
||||
mod sub_app;
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
mod task_pool_plugin;
|
||||
#[cfg(all(any(unix, windows), feature = "std"))]
|
||||
mod terminal_ctrl_c_handler;
|
||||
@ -42,7 +41,6 @@ pub use plugin::*;
|
||||
pub use plugin_group::*;
|
||||
pub use schedule_runner::*;
|
||||
pub use sub_app::*;
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
pub use task_pool_plugin::*;
|
||||
#[cfg(all(any(unix, windows), feature = "std"))]
|
||||
pub use terminal_ctrl_c_handler::*;
|
||||
@ -60,10 +58,6 @@ pub mod prelude {
|
||||
RunFixedMainLoopSystem, SpawnScene, Startup, Update,
|
||||
},
|
||||
sub_app::SubApp,
|
||||
Plugin, PluginGroup,
|
||||
NonSendMarker, Plugin, PluginGroup, TaskPoolOptions, TaskPoolPlugin,
|
||||
};
|
||||
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::{NonSendMarker, TaskPoolOptions, TaskPoolPlugin};
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ impl Plugin for ScheduleRunnerPlugin {
|
||||
let plugins_state = app.plugins_state();
|
||||
if plugins_state != PluginsState::Cleaned {
|
||||
while app.plugins_state() == PluginsState::Adding {
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "bevy_tasks"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
bevy_tasks::tick_global_task_pools_on_main_thread();
|
||||
}
|
||||
app.finish();
|
||||
|
@ -14,9 +14,7 @@ bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
|
||||
|
||||
|
@ -26,7 +26,7 @@ serialize = [
|
||||
dynamic_linking = []
|
||||
|
||||
## Adds integration with `sysinfo`.
|
||||
sysinfo_plugin = ["sysinfo", "dep:bevy_tasks"]
|
||||
sysinfo_plugin = ["sysinfo"]
|
||||
|
||||
# Platform Compatibility
|
||||
|
||||
@ -40,7 +40,7 @@ std = [
|
||||
"bevy_platform_support/std",
|
||||
"bevy_time/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_tasks?/std",
|
||||
"bevy_tasks/std",
|
||||
]
|
||||
|
||||
## `critical-section` provides the building blocks for synchronization primitives
|
||||
@ -51,7 +51,7 @@ critical-section = [
|
||||
"bevy_platform_support/critical-section",
|
||||
"bevy_time/critical-section",
|
||||
"bevy_utils/critical-section",
|
||||
"bevy_tasks?/critical-section",
|
||||
"bevy_tasks/critical-section",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
@ -62,7 +62,7 @@ bevy_time = { path = "../bevy_time", version = "0.16.0-dev", default-features =
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
|
@ -60,11 +60,7 @@ track_location = []
|
||||
|
||||
## Uses `async-executor` as a task execution backend.
|
||||
## This backend is incompatible with `no_std` targets.
|
||||
async_executor = ["dep:bevy_tasks", "std", "bevy_tasks/async_executor"]
|
||||
|
||||
## Uses `edge-executor` as a task execution backend.
|
||||
## Use this instead of `async-executor` if working on a `no_std` target.
|
||||
edge_executor = ["dep:bevy_tasks", "bevy_tasks/edge_executor"]
|
||||
async_executor = ["std", "bevy_tasks/async_executor"]
|
||||
|
||||
# Platform Compatibility
|
||||
|
||||
@ -90,7 +86,7 @@ std = [
|
||||
## `critical-section` provides the building blocks for synchronization primitives
|
||||
## on all platforms, including `no_std`.
|
||||
critical-section = [
|
||||
"bevy_tasks?/critical-section",
|
||||
"bevy_tasks/critical-section",
|
||||
"bevy_platform_support/critical-section",
|
||||
"bevy_reflect?/critical-section",
|
||||
]
|
||||
@ -100,7 +96,7 @@ bevy_ptr = { path = "../bevy_ptr", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"smallvec",
|
||||
], default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
|
@ -13,10 +13,11 @@ use alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeSet, BinaryHeap, LinkedList, VecDeque},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use bevy_platform_support::sync::Arc;
|
||||
|
||||
use super::{unique_slice, TrustedEntityBorrow, UniqueEntityIter, UniqueEntitySlice};
|
||||
|
||||
/// An array that contains only unique entities.
|
||||
@ -73,9 +74,9 @@ impl<T: TrustedEntityBorrow, const N: usize> UniqueEntityArray<T, N> {
|
||||
}
|
||||
|
||||
/// Casts `self` to the inner array.
|
||||
pub fn into_arc_inner(self: Arc<Self>) -> Arc<[T; N]> {
|
||||
pub fn into_arc_inner(this: Arc<Self>) -> Arc<[T; N]> {
|
||||
// SAFETY: UniqueEntityArray is a transparent wrapper around [T; N].
|
||||
unsafe { Arc::from_raw(Arc::into_raw(self).cast()) }
|
||||
unsafe { Arc::from_raw(Arc::into_raw(this).cast()) }
|
||||
}
|
||||
|
||||
// Constructs a `Rc<UniqueEntityArray>` from a [`Rc<[T; N]>`] unsafely.
|
||||
|
@ -17,10 +17,11 @@ use alloc::{
|
||||
boxed::Box,
|
||||
collections::VecDeque,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use bevy_platform_support::sync::Arc;
|
||||
|
||||
use super::{
|
||||
unique_vec, EntitySet, EntitySetIterator, FromEntitySetIterator, TrustedEntityBorrow,
|
||||
UniqueEntityArray, UniqueEntityIter, UniqueEntityVec,
|
||||
@ -86,9 +87,9 @@ impl<T: TrustedEntityBorrow> UniqueEntitySlice<T> {
|
||||
}
|
||||
|
||||
/// Casts `self` to the inner slice.
|
||||
pub fn into_arc_inner(self: Arc<Self>) -> Arc<[T]> {
|
||||
pub fn into_arc_inner(this: Arc<Self>) -> Arc<[T]> {
|
||||
// SAFETY: UniqueEntitySlice is a transparent wrapper around [T].
|
||||
unsafe { Arc::from_raw(Arc::into_raw(self) as *mut [T]) }
|
||||
unsafe { Arc::from_raw(Arc::into_raw(this) as *mut [T]) }
|
||||
}
|
||||
|
||||
// Constructs a `UniqueEntitySlice` from a [`Rc<[T]>`] unsafely.
|
||||
|
@ -12,10 +12,11 @@ use alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeSet, BinaryHeap, TryReserveError, VecDeque},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
vec::{self, Vec},
|
||||
};
|
||||
|
||||
use bevy_platform_support::sync::Arc;
|
||||
|
||||
use super::{
|
||||
unique_slice, EntitySet, FromEntitySetIterator, TrustedEntityBorrow, UniqueEntityArray,
|
||||
UniqueEntityIter, UniqueEntitySlice,
|
||||
|
@ -28,9 +28,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_pbr = { path = "../bevy_pbr", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
|
||||
bevy_scene = { path = "../bevy_scene", version = "0.16.0-dev", features = [
|
||||
"bevy_render",
|
||||
|
@ -49,9 +49,7 @@ bevy_color = { path = "../bevy_color", version = "0.16.0-dev", features = [
|
||||
"wgpu-types",
|
||||
] }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
], optional = true }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", optional = true }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [
|
||||
"std",
|
||||
|
@ -90,6 +90,7 @@ shader_format_glsl = [
|
||||
shader_format_spirv = ["bevy_render/shader_format_spirv"]
|
||||
|
||||
serialize = [
|
||||
"bevy_a11y?/serialize",
|
||||
"bevy_color?/serialize",
|
||||
"bevy_ecs/serialize",
|
||||
"bevy_image?/serialize",
|
||||
@ -104,12 +105,13 @@ serialize = [
|
||||
"bevy_platform_support/serialize",
|
||||
]
|
||||
multi_threaded = [
|
||||
"std",
|
||||
"bevy_asset?/multi_threaded",
|
||||
"bevy_ecs/multi_threaded",
|
||||
"bevy_render?/multi_threaded",
|
||||
"bevy_tasks/multi_threaded",
|
||||
]
|
||||
async-io = ["bevy_tasks/async-io"]
|
||||
async-io = ["std", "bevy_tasks/async-io"]
|
||||
|
||||
# Display server protocol support (X11 is enabled by default)
|
||||
wayland = ["bevy_winit/wayland"]
|
||||
@ -195,6 +197,8 @@ bevy_render = [
|
||||
"bevy_scene?/bevy_render",
|
||||
"bevy_gizmos?/bevy_render",
|
||||
"bevy_image",
|
||||
"bevy_color/wgpu-types",
|
||||
"bevy_color/encase",
|
||||
]
|
||||
|
||||
# Enable assertions to check the validity of parameters passed to glam
|
||||
@ -275,49 +279,133 @@ custom_cursor = ["bevy_winit/custom_cursor"]
|
||||
# Experimental support for nodes that are ignored for UI layouting
|
||||
ghost_nodes = ["bevy_ui/ghost_nodes"]
|
||||
|
||||
# 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_a11y?/std",
|
||||
"bevy_app/std",
|
||||
"bevy_color?/std",
|
||||
"bevy_diagnostic/std",
|
||||
"bevy_ecs/std",
|
||||
"bevy_input/std",
|
||||
"bevy_input_focus?/std",
|
||||
"bevy_math/std",
|
||||
"bevy_platform_support/std",
|
||||
"bevy_reflect/std",
|
||||
"bevy_state?/std",
|
||||
"bevy_time/std",
|
||||
"bevy_transform/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_tasks/std",
|
||||
"bevy_window?/std",
|
||||
]
|
||||
|
||||
# `critical-section` provides the building blocks for synchronization primitives
|
||||
# on all platforms, including `no_std`.
|
||||
critical-section = [
|
||||
"bevy_a11y?/critical-section",
|
||||
"bevy_app/critical-section",
|
||||
"bevy_diagnostic/critical-section",
|
||||
"bevy_ecs/critical-section",
|
||||
"bevy_input/critical-section",
|
||||
"bevy_input_focus?/critical-section",
|
||||
"bevy_platform_support/critical-section",
|
||||
"bevy_reflect/critical-section",
|
||||
"bevy_state?/critical-section",
|
||||
"bevy_time/critical-section",
|
||||
"bevy_utils/critical-section",
|
||||
"bevy_tasks/critical-section",
|
||||
]
|
||||
|
||||
# Uses the `libm` maths library instead of the one provided in `std` and `core`.
|
||||
libm = [
|
||||
"bevy_a11y?/libm",
|
||||
"bevy_color?/libm",
|
||||
"bevy_input/libm",
|
||||
"bevy_input_focus?/libm",
|
||||
"bevy_math/libm",
|
||||
"bevy_transform/libm",
|
||||
"bevy_window?/libm",
|
||||
]
|
||||
|
||||
# Uses `async-executor` as a task execution backend.
|
||||
# This backend is incompatible with `no_std` targets.
|
||||
async_executor = ["std", "bevy_tasks/async_executor", "bevy_ecs/async_executor"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_a11y = { path = "../bevy_a11y", version = "0.16.0-dev", optional = true }
|
||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_state = { path = "../bevy_state", optional = true, version = "0.16.0-dev" }
|
||||
bevy_input = { path = "../bevy_input", version = "0.16.0-dev" }
|
||||
bevy_input_focus = { path = "../bevy_input_focus", version = "0.16.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev", features = [
|
||||
# bevy (no_std)
|
||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev" }
|
||||
bevy_ptr = { path = "../bevy_ptr", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev", default-features = false }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev", default-features = false }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
||||
bevy_window = { path = "../bevy_window", version = "0.16.0-dev", optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev" }
|
||||
bevy_input = { path = "../bevy_input", version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
], optional = true }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
], optional = true }
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
bevy_ptr = { path = "../bevy_ptr", version = "0.16.0-dev", default-features = false }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
|
||||
"smallvec",
|
||||
] }
|
||||
bevy_time = { path = "../bevy_time", version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy-support",
|
||||
"bevy_reflect",
|
||||
], optional = true }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
|
||||
|
||||
# bevy (std required)
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev", optional = true }
|
||||
|
||||
# bevy (optional)
|
||||
bevy_a11y = { path = "../bevy_a11y", optional = true, version = "0.16.0-dev", features = [
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_animation = { path = "../bevy_animation", optional = true, version = "0.16.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", optional = true, version = "0.16.0-dev" }
|
||||
bevy_audio = { path = "../bevy_audio", optional = true, version = "0.16.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", optional = true, version = "0.16.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", optional = true, version = "0.16.0-dev", default-features = false, features = [
|
||||
"alloc",
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.16.0-dev" }
|
||||
bevy_dev_tools = { path = "../bevy_dev_tools", optional = true, version = "0.16.0-dev" }
|
||||
bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.16.0-dev" }
|
||||
bevy_gizmos = { path = "../bevy_gizmos", optional = true, version = "0.16.0-dev", default-features = false }
|
||||
bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", optional = true, version = "0.16.0-dev" }
|
||||
bevy_input_focus = { path = "../bevy_input_focus", optional = true, version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.16.0-dev" }
|
||||
bevy_picking = { path = "../bevy_picking", optional = true, version = "0.16.0-dev" }
|
||||
bevy_remote = { path = "../bevy_remote", optional = true, version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", optional = true, version = "0.16.0-dev" }
|
||||
bevy_scene = { path = "../bevy_scene", optional = true, version = "0.16.0-dev" }
|
||||
bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.16.0-dev" }
|
||||
bevy_state = { path = "../bevy_state", optional = true, version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_app",
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_text = { path = "../bevy_text", optional = true, version = "0.16.0-dev" }
|
||||
bevy_ui = { path = "../bevy_ui", optional = true, version = "0.16.0-dev" }
|
||||
bevy_window = { path = "../bevy_window", optional = true, version = "0.16.0-dev", default-features = false, features = [
|
||||
"bevy_reflect",
|
||||
] }
|
||||
bevy_winit = { path = "../bevy_winit", optional = true, version = "0.16.0-dev" }
|
||||
|
||||
[lints]
|
||||
|
@ -4,12 +4,15 @@ plugin_group! {
|
||||
/// This plugin group will add all the default plugins for a *Bevy* application:
|
||||
pub struct DefaultPlugins {
|
||||
bevy_app:::PanicHandlerPlugin,
|
||||
#[cfg(feature = "bevy_log")]
|
||||
bevy_log:::LogPlugin,
|
||||
bevy_app:::TaskPoolPlugin,
|
||||
bevy_diagnostic:::FrameCountPlugin,
|
||||
bevy_time:::TimePlugin,
|
||||
#[custom(cfg(any(feature = "libm", feature = "std")))]
|
||||
bevy_transform:::TransformPlugin,
|
||||
bevy_diagnostic:::DiagnosticsPlugin,
|
||||
#[custom(cfg(any(feature = "libm", feature = "std")))]
|
||||
bevy_input:::InputPlugin,
|
||||
#[custom(cfg(not(feature = "bevy_window")))]
|
||||
bevy_app:::ScheduleRunnerPlugin,
|
||||
@ -17,6 +20,7 @@ plugin_group! {
|
||||
bevy_window:::WindowPlugin,
|
||||
#[cfg(feature = "bevy_window")]
|
||||
bevy_a11y:::AccessibilityPlugin,
|
||||
#[cfg(feature = "std")]
|
||||
#[custom(cfg(any(unix, windows)))]
|
||||
bevy_app:::TerminalCtrlCHandlerPlugin,
|
||||
#[cfg(feature = "bevy_asset")]
|
||||
|
@ -4,6 +4,7 @@
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
||||
)]
|
||||
#![no_std]
|
||||
|
||||
//! This module is separated into its own crate to enable simple dynamic linking for Bevy, and should not be used directly
|
||||
|
||||
@ -38,9 +39,13 @@ pub use bevy_gizmos as gizmos;
|
||||
pub use bevy_gltf as gltf;
|
||||
#[cfg(feature = "bevy_image")]
|
||||
pub use bevy_image as image;
|
||||
#[cfg(any(feature = "libm", feature = "std"))]
|
||||
pub use bevy_input as input;
|
||||
#[cfg(feature = "bevy_input_focus")]
|
||||
pub use bevy_input_focus as input_focus;
|
||||
#[cfg(feature = "bevy_log")]
|
||||
pub use bevy_log as log;
|
||||
#[cfg(any(feature = "libm", feature = "std"))]
|
||||
pub use bevy_math as math;
|
||||
#[cfg(feature = "bevy_pbr")]
|
||||
pub use bevy_pbr as pbr;
|
||||
@ -63,6 +68,7 @@ pub use bevy_tasks as tasks;
|
||||
#[cfg(feature = "bevy_text")]
|
||||
pub use bevy_text as text;
|
||||
pub use bevy_time as time;
|
||||
#[cfg(any(feature = "libm", feature = "std"))]
|
||||
pub use bevy_transform as transform;
|
||||
#[cfg(feature = "bevy_ui")]
|
||||
pub use bevy_ui as ui;
|
||||
|
@ -1,10 +1,17 @@
|
||||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
app::prelude::*, ecs::prelude::*, input::prelude::*, log::prelude::*, math::prelude::*,
|
||||
reflect::prelude::*, time::prelude::*, transform::prelude::*, utils::prelude::*,
|
||||
app::prelude::*, ecs::prelude::*, reflect::prelude::*, time::prelude::*, utils::prelude::*,
|
||||
DefaultPlugins, MinimalPlugins,
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(any(feature = "libm", feature = "std"))]
|
||||
pub use crate::{input::prelude::*, math::prelude::*, transform::prelude::*};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "bevy_log")]
|
||||
pub use crate::log::prelude::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "bevy_window")]
|
||||
pub use crate::window::prelude::*;
|
||||
|
@ -13,9 +13,7 @@ keywords = ["bevy"]
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.16.0-dev" }
|
||||
|
@ -40,9 +40,7 @@ bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", optional = true }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
|
@ -45,12 +45,7 @@ This is explicitly incompatible with `no_std` targets.
|
||||
Enables usage of the [`alloc`](https://doc.rust-lang.org/stable/alloc/) crate. Note that this feature is automatically enabled when enabling `std`.
|
||||
This is compatible with most `no_std` targets, but not all.
|
||||
|
||||
### `portable-atomic`
|
||||
|
||||
Switches to using [`portable-atomic`](https://docs.rs/portable-atomic/latest/portable_atomic/) as a backend for atomic types, such as `Arc`, `AtomicU8`, etc.
|
||||
You may need to enable this feature on platforms without full support for atomic types or certain operations, such as [atomic CAS](https://en.wikipedia.org/wiki/Compare-and-swap).
|
||||
|
||||
### `critical-section`
|
||||
|
||||
Switches to using [`critical-section`](https://docs.rs/critical-section/latest/critical_section/) as a backend for synchronization.
|
||||
You may need to enable this feature on platforms with little to no support for atomic operations, and is often paired with the `portable-atomic` feature.
|
||||
You may need to enable this feature on platforms with little to no support for atomic operations.
|
||||
|
@ -20,9 +20,6 @@ documentation = ["bevy_reflect_derive/documentation"]
|
||||
## Enables function reflection
|
||||
functions = ["bevy_reflect_derive/functions"]
|
||||
|
||||
# When enabled, provides Bevy-related reflection implementations
|
||||
bevy = ["smallvec", "smol_str"]
|
||||
|
||||
# Debugging Features
|
||||
|
||||
## Enables features useful for debugging reflection
|
||||
|
@ -48,9 +48,7 @@ bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_render_macros = { path = "macros", version = "0.16.0-dev" }
|
||||
bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
|
@ -23,9 +23,7 @@ bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev", optional = true }
|
||||
|
@ -23,9 +23,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_picking = { path = "../bevy_picking", version = "0.16.0-dev", optional = true }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
||||
|
@ -13,16 +13,12 @@ default = ["std", "async_executor"]
|
||||
std = [
|
||||
"futures-lite/std",
|
||||
"async-task/std",
|
||||
"edge-executor?/std",
|
||||
"bevy_platform_support/std",
|
||||
"once_cell/std",
|
||||
]
|
||||
multi_threaded = ["std", "dep:async-channel", "dep:concurrent-queue"]
|
||||
async_executor = ["std", "dep:async-executor"]
|
||||
edge_executor = ["dep:edge-executor"]
|
||||
critical-section = [
|
||||
"bevy_platform_support/critical-section",
|
||||
"edge-executor?/critical-section",
|
||||
]
|
||||
critical-section = ["bevy_platform_support/critical-section"]
|
||||
|
||||
[dependencies]
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [
|
||||
@ -37,12 +33,17 @@ derive_more = { version = "1", default-features = false, features = [
|
||||
"deref",
|
||||
"deref_mut",
|
||||
] }
|
||||
|
||||
async-executor = { version = "1.11", optional = true }
|
||||
edge-executor = { version = "0.4.1", default-features = false, optional = true }
|
||||
async-channel = { version = "2.3.0", optional = true }
|
||||
async-io = { version = "2.0.0", optional = true }
|
||||
concurrent-queue = { version = "2.0.0", optional = true }
|
||||
atomic-waker = { version = "1", default-features = false }
|
||||
once_cell = { version = "1.18", default-features = false, features = [
|
||||
"critical-section",
|
||||
] }
|
||||
crossbeam-queue = { version = "0.3", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen-futures = "0.4"
|
||||
@ -53,7 +54,10 @@ futures-channel = "0.3"
|
||||
async-task = { version = "4.4.0", default-features = false, features = [
|
||||
"portable-atomic",
|
||||
] }
|
||||
edge-executor = { version = "0.4.1", default-features = false, optional = true, features = [
|
||||
heapless = { version = "0.8", default-features = false, features = [
|
||||
"portable-atomic",
|
||||
] }
|
||||
atomic-waker = { version = "1", default-features = false, features = [
|
||||
"portable-atomic",
|
||||
] }
|
||||
|
||||
|
@ -36,7 +36,7 @@ The determining factor for what kind of work should go in each pool is latency r
|
||||
|
||||
## `no_std` Support
|
||||
|
||||
To enable `no_std` support in this crate, you will need to disable default features, and enable the `edge_executor` and `critical-section` features. For platforms without full support for Rust atomics, you may also need to enable the `portable-atomic` feature.
|
||||
To enable `no_std` support in this crate, you will need to disable default features, and enable the `edge_executor` and `critical-section` features.
|
||||
|
||||
[bevy]: https://bevyengine.org
|
||||
[rayon]: https://github.com/rayon-rs/rayon
|
||||
|
653
crates/bevy_tasks/src/edge_executor.rs
Normal file
653
crates/bevy_tasks/src/edge_executor.rs
Normal file
@ -0,0 +1,653 @@
|
||||
//! Alternative to `async_executor` based on [`edge_executor`] by Ivan Markov.
|
||||
//!
|
||||
//! It has been vendored along with its tests to update several outdated dependencies.
|
||||
//!
|
||||
//! [`async_executor`]: https://github.com/smol-rs/async-executor
|
||||
//! [`edge_executor`]: https://github.com/ivmarkov/edge-executor
|
||||
|
||||
#![expect(unsafe_code, reason = "original implementation relies on unsafe")]
|
||||
#![expect(
|
||||
dead_code,
|
||||
reason = "keeping methods from original implementation for transparency"
|
||||
)]
|
||||
|
||||
// TODO: Create a more tailored replacement, possibly integrating [Fotre](https://github.com/NthTensor/Forte)
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use core::{
|
||||
future::{poll_fn, Future},
|
||||
marker::PhantomData,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use async_task::{Runnable, Task};
|
||||
use atomic_waker::AtomicWaker;
|
||||
use bevy_platform_support::sync::Arc;
|
||||
use futures_lite::FutureExt;
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
/// An async executor.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A multi-threaded executor:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use async_channel::unbounded;
|
||||
/// use easy_parallel::Parallel;
|
||||
///
|
||||
/// use edge_executor::{Executor, block_on};
|
||||
///
|
||||
/// let ex: Executor = Default::default();
|
||||
/// let (signal, shutdown) = unbounded::<()>();
|
||||
///
|
||||
/// Parallel::new()
|
||||
/// // Run four executor threads.
|
||||
/// .each(0..4, |_| block_on(ex.run(shutdown.recv())))
|
||||
/// // Run the main future on the current thread.
|
||||
/// .finish(|| block_on(async {
|
||||
/// println!("Hello world!");
|
||||
/// drop(signal);
|
||||
/// }));
|
||||
/// ```
|
||||
pub struct Executor<'a, const C: usize = 64> {
|
||||
state: OnceCell<Arc<State<C>>>,
|
||||
_invariant: PhantomData<core::cell::UnsafeCell<&'a ()>>,
|
||||
}
|
||||
|
||||
impl<'a, const C: usize> Executor<'a, C> {
|
||||
/// Creates a new executor.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::Executor;
|
||||
///
|
||||
/// let ex: Executor = Default::default();
|
||||
/// ```
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
state: OnceCell::new(),
|
||||
_invariant: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawns a task onto the executor.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::Executor;
|
||||
///
|
||||
/// let ex: Executor = Default::default();
|
||||
///
|
||||
/// let task = ex.spawn(async {
|
||||
/// println!("Hello world");
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Note that if the executor's queue size is equal to the number of currently
|
||||
/// spawned and running tasks, spawning this additional task might cause the executor to panic
|
||||
/// later, when the task is scheduled for polling.
|
||||
pub fn spawn<F>(&self, fut: F) -> Task<F::Output>
|
||||
where
|
||||
F: Future + Send + 'a,
|
||||
F::Output: Send + 'a,
|
||||
{
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
unsafe { self.spawn_unchecked(fut) }
|
||||
}
|
||||
|
||||
/// Attempts to run a task if at least one is scheduled.
|
||||
///
|
||||
/// Running a scheduled task means simply polling its future once.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::Executor;
|
||||
///
|
||||
/// let ex: Executor = Default::default();
|
||||
/// assert!(!ex.try_tick()); // no tasks to run
|
||||
///
|
||||
/// let task = ex.spawn(async {
|
||||
/// println!("Hello world");
|
||||
/// });
|
||||
/// assert!(ex.try_tick()); // a task was found
|
||||
/// ```
|
||||
pub fn try_tick(&self) -> bool {
|
||||
if let Some(runnable) = self.try_runnable() {
|
||||
runnable.run();
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs a single task asynchronously.
|
||||
///
|
||||
/// Running a task means simply polling its future once.
|
||||
///
|
||||
/// If no tasks are scheduled when this method is called, it will wait until one is scheduled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::{Executor, block_on};
|
||||
///
|
||||
/// let ex: Executor = Default::default();
|
||||
///
|
||||
/// let task = ex.spawn(async {
|
||||
/// println!("Hello world");
|
||||
/// });
|
||||
/// block_on(ex.tick()); // runs the task
|
||||
/// ```
|
||||
pub async fn tick(&self) {
|
||||
self.runnable().await.run();
|
||||
}
|
||||
|
||||
/// Runs the executor asynchronously until the given future completes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::{Executor, block_on};
|
||||
///
|
||||
/// let ex: Executor = Default::default();
|
||||
///
|
||||
/// let task = ex.spawn(async { 1 + 2 });
|
||||
/// let res = block_on(ex.run(async { task.await * 2 }));
|
||||
///
|
||||
/// assert_eq!(res, 6);
|
||||
/// ```
|
||||
pub async fn run<F>(&self, fut: F) -> F::Output
|
||||
where
|
||||
F: Future + Send + 'a,
|
||||
{
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
unsafe { self.run_unchecked(fut).await }
|
||||
}
|
||||
|
||||
/// Waits for the next runnable task to run.
|
||||
async fn runnable(&self) -> Runnable {
|
||||
poll_fn(|ctx| self.poll_runnable(ctx)).await
|
||||
}
|
||||
|
||||
/// Polls the first task scheduled for execution by the executor.
|
||||
fn poll_runnable(&self, ctx: &Context<'_>) -> Poll<Runnable> {
|
||||
self.state().waker.register(ctx.waker());
|
||||
|
||||
if let Some(runnable) = self.try_runnable() {
|
||||
Poll::Ready(runnable)
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
/// Pops the first task scheduled for execution by the executor.
|
||||
///
|
||||
/// Returns
|
||||
/// - `None` - if no task was scheduled for execution
|
||||
/// - `Some(Runnnable)` - the first task scheduled for execution. Calling `Runnable::run` will
|
||||
/// execute the task. In other words, it will poll its future.
|
||||
fn try_runnable(&self) -> Option<Runnable> {
|
||||
let runnable;
|
||||
|
||||
#[cfg(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
))]
|
||||
{
|
||||
runnable = self.state().queue.pop();
|
||||
}
|
||||
|
||||
#[cfg(not(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
)))]
|
||||
{
|
||||
runnable = self.state().queue.dequeue();
|
||||
}
|
||||
|
||||
runnable
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Original implementation missing safety documentation
|
||||
unsafe fn spawn_unchecked<F>(&self, fut: F) -> Task<F::Output>
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
let schedule = {
|
||||
let state = self.state().clone();
|
||||
|
||||
move |runnable| {
|
||||
#[cfg(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
))]
|
||||
{
|
||||
state.queue.push(runnable).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
)))]
|
||||
{
|
||||
state.queue.enqueue(runnable).unwrap();
|
||||
}
|
||||
|
||||
if let Some(waker) = state.waker.take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
let (runnable, task) = unsafe { async_task::spawn_unchecked(fut, schedule) };
|
||||
|
||||
runnable.schedule();
|
||||
|
||||
task
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Original implementation missing safety documentation
|
||||
async unsafe fn run_unchecked<F>(&self, fut: F) -> F::Output
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
let run_forever = async {
|
||||
loop {
|
||||
self.tick().await;
|
||||
}
|
||||
};
|
||||
|
||||
run_forever.or(fut).await
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner state.
|
||||
fn state(&self) -> &Arc<State<C>> {
|
||||
self.state.get_or_init(|| Arc::new(State::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const C: usize> Default for Executor<'a, C> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
unsafe impl<'a, const C: usize> Send for Executor<'a, C> {}
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
unsafe impl<'a, const C: usize> Sync for Executor<'a, C> {}
|
||||
|
||||
/// A thread-local executor.
|
||||
///
|
||||
/// The executor can only be run on the thread that created it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::{LocalExecutor, block_on};
|
||||
///
|
||||
/// let local_ex: LocalExecutor = Default::default();
|
||||
///
|
||||
/// block_on(local_ex.run(async {
|
||||
/// println!("Hello world!");
|
||||
/// }));
|
||||
/// ```
|
||||
pub struct LocalExecutor<'a, const C: usize = 64> {
|
||||
executor: Executor<'a, C>,
|
||||
_not_send: PhantomData<core::cell::UnsafeCell<&'a Rc<()>>>,
|
||||
}
|
||||
|
||||
impl<'a, const C: usize> LocalExecutor<'a, C> {
|
||||
/// Creates a single-threaded executor.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::LocalExecutor;
|
||||
///
|
||||
/// let local_ex: LocalExecutor = Default::default();
|
||||
/// ```
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
executor: Executor::<C>::new(),
|
||||
_not_send: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawns a task onto the executor.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::LocalExecutor;
|
||||
///
|
||||
/// let local_ex: LocalExecutor = Default::default();
|
||||
///
|
||||
/// let task = local_ex.spawn(async {
|
||||
/// println!("Hello world");
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Note that if the executor's queue size is equal to the number of currently
|
||||
/// spawned and running tasks, spawning this additional task might cause the executor to panic
|
||||
/// later, when the task is scheduled for polling.
|
||||
pub fn spawn<F>(&self, fut: F) -> Task<F::Output>
|
||||
where
|
||||
F: Future + 'a,
|
||||
F::Output: 'a,
|
||||
{
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
unsafe { self.executor.spawn_unchecked(fut) }
|
||||
}
|
||||
|
||||
/// Attempts to run a task if at least one is scheduled.
|
||||
///
|
||||
/// Running a scheduled task means simply polling its future once.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::LocalExecutor;
|
||||
///
|
||||
/// let local_ex: LocalExecutor = Default::default();
|
||||
/// assert!(!local_ex.try_tick()); // no tasks to run
|
||||
///
|
||||
/// let task = local_ex.spawn(async {
|
||||
/// println!("Hello world");
|
||||
/// });
|
||||
/// assert!(local_ex.try_tick()); // a task was found
|
||||
/// ```
|
||||
pub fn try_tick(&self) -> bool {
|
||||
self.executor.try_tick()
|
||||
}
|
||||
|
||||
/// Runs a single task asynchronously.
|
||||
///
|
||||
/// Running a task means simply polling its future once.
|
||||
///
|
||||
/// If no tasks are scheduled when this method is called, it will wait until one is scheduled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::{LocalExecutor, block_on};
|
||||
///
|
||||
/// let local_ex: LocalExecutor = Default::default();
|
||||
///
|
||||
/// let task = local_ex.spawn(async {
|
||||
/// println!("Hello world");
|
||||
/// });
|
||||
/// block_on(local_ex.tick()); // runs the task
|
||||
/// ```
|
||||
pub async fn tick(&self) {
|
||||
self.executor.tick().await;
|
||||
}
|
||||
|
||||
/// Runs the executor asynchronously until the given future completes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use edge_executor::{LocalExecutor, block_on};
|
||||
///
|
||||
/// let local_ex: LocalExecutor = Default::default();
|
||||
///
|
||||
/// let task = local_ex.spawn(async { 1 + 2 });
|
||||
/// let res = block_on(local_ex.run(async { task.await * 2 }));
|
||||
///
|
||||
/// assert_eq!(res, 6);
|
||||
/// ```
|
||||
pub async fn run<F>(&self, fut: F) -> F::Output
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
// SAFETY: Original implementation missing safety documentation
|
||||
unsafe { self.executor.run_unchecked(fut) }.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const C: usize> Default for LocalExecutor<'a, C> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
struct State<const C: usize> {
|
||||
#[cfg(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
))]
|
||||
queue: crossbeam_queue::ArrayQueue<Runnable>,
|
||||
#[cfg(not(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
)))]
|
||||
queue: heapless::mpmc::MpMcQueue<Runnable, C>,
|
||||
waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl<const C: usize> State<C> {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
#[cfg(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
))]
|
||||
queue: crossbeam_queue::ArrayQueue::new(C),
|
||||
#[cfg(not(all(
|
||||
target_has_atomic = "8",
|
||||
target_has_atomic = "16",
|
||||
target_has_atomic = "32",
|
||||
target_has_atomic = "64",
|
||||
target_has_atomic = "ptr"
|
||||
)))]
|
||||
queue: heapless::mpmc::MpMcQueue::new(),
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod different_executor_tests {
|
||||
use core::cell::Cell;
|
||||
|
||||
use futures_lite::future::{block_on, pending, poll_once};
|
||||
use futures_lite::pin;
|
||||
|
||||
use super::LocalExecutor;
|
||||
|
||||
#[test]
|
||||
fn shared_queue_slot() {
|
||||
block_on(async {
|
||||
let was_polled = Cell::new(false);
|
||||
let future = async {
|
||||
was_polled.set(true);
|
||||
pending::<()>().await;
|
||||
};
|
||||
|
||||
let ex1: LocalExecutor = Default::default();
|
||||
let ex2: LocalExecutor = Default::default();
|
||||
|
||||
// Start the futures for running forever.
|
||||
let (run1, run2) = (ex1.run(pending::<()>()), ex2.run(pending::<()>()));
|
||||
pin!(run1);
|
||||
pin!(run2);
|
||||
assert!(poll_once(run1.as_mut()).await.is_none());
|
||||
assert!(poll_once(run2.as_mut()).await.is_none());
|
||||
|
||||
// Spawn the future on executor one and then poll executor two.
|
||||
ex1.spawn(future).detach();
|
||||
assert!(poll_once(run2).await.is_none());
|
||||
assert!(!was_polled.get());
|
||||
|
||||
// Poll the first one.
|
||||
assert!(poll_once(run1).await.is_none());
|
||||
assert!(was_polled.get());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod drop_tests {
|
||||
use alloc::string::String;
|
||||
use core::mem;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::task::{Poll, Waker};
|
||||
use std::sync::Mutex;
|
||||
|
||||
use futures_lite::future;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use super::{Executor, Task};
|
||||
|
||||
#[test]
|
||||
fn leaked_executor_leaks_everything() {
|
||||
static DROP: AtomicUsize = AtomicUsize::new(0);
|
||||
static WAKER: Lazy<Mutex<Option<Waker>>> = Lazy::new(Default::default);
|
||||
|
||||
let ex: Executor = Default::default();
|
||||
|
||||
let task = ex.spawn(async {
|
||||
let _guard = CallOnDrop(|| {
|
||||
DROP.fetch_add(1, Ordering::SeqCst);
|
||||
});
|
||||
|
||||
future::poll_fn(|cx| {
|
||||
*WAKER.lock().unwrap() = Some(cx.waker().clone());
|
||||
Poll::Pending::<()>
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
||||
future::block_on(ex.tick());
|
||||
assert!(WAKER.lock().unwrap().is_some());
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 0);
|
||||
|
||||
mem::forget(ex);
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 0);
|
||||
|
||||
assert!(future::block_on(future::poll_once(task)).is_none());
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn await_task_after_dropping_executor() {
|
||||
let s: String = "hello".into();
|
||||
|
||||
let ex: Executor = Default::default();
|
||||
let task: Task<&str> = ex.spawn(async { &*s });
|
||||
assert!(ex.try_tick());
|
||||
|
||||
drop(ex);
|
||||
assert_eq!(future::block_on(task), "hello");
|
||||
drop(s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_executor_and_then_drop_finished_task() {
|
||||
static DROP: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
let ex: Executor = Default::default();
|
||||
let task = ex.spawn(async {
|
||||
CallOnDrop(|| {
|
||||
DROP.fetch_add(1, Ordering::SeqCst);
|
||||
})
|
||||
});
|
||||
assert!(ex.try_tick());
|
||||
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 0);
|
||||
drop(ex);
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 0);
|
||||
drop(task);
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_finished_task_and_then_drop_executor() {
|
||||
static DROP: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
let ex: Executor = Default::default();
|
||||
let task = ex.spawn(async {
|
||||
CallOnDrop(|| {
|
||||
DROP.fetch_add(1, Ordering::SeqCst);
|
||||
})
|
||||
});
|
||||
assert!(ex.try_tick());
|
||||
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 0);
|
||||
drop(task);
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 1);
|
||||
drop(ex);
|
||||
assert_eq!(DROP.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
||||
struct CallOnDrop<F: Fn()>(F);
|
||||
|
||||
impl<F: Fn()> Drop for CallOnDrop<F> {
|
||||
fn drop(&mut self) {
|
||||
(self.0)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod local_queue {
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use futures_lite::{future, pin};
|
||||
|
||||
use super::Executor;
|
||||
|
||||
#[test]
|
||||
fn two_queues() {
|
||||
future::block_on(async {
|
||||
// Create an executor with two runners.
|
||||
let ex: Executor = Default::default();
|
||||
let (run1, run2) = (
|
||||
ex.run(future::pending::<()>()),
|
||||
ex.run(future::pending::<()>()),
|
||||
);
|
||||
let mut run1 = Box::pin(run1);
|
||||
pin!(run2);
|
||||
|
||||
// Poll them both.
|
||||
assert!(future::poll_once(run1.as_mut()).await.is_none());
|
||||
assert!(future::poll_once(run2.as_mut()).await.is_none());
|
||||
|
||||
// Drop the first one, which should leave the local queue in the `None` state.
|
||||
drop(run1);
|
||||
assert!(future::poll_once(run2.as_mut()).await.is_none());
|
||||
});
|
||||
}
|
||||
}
|
@ -23,11 +23,11 @@ type ExecutorInner<'a> = async_executor::Executor<'a>;
|
||||
#[cfg(feature = "async_executor")]
|
||||
type LocalExecutorInner<'a> = async_executor::LocalExecutor<'a>;
|
||||
|
||||
#[cfg(all(not(feature = "async_executor"), feature = "edge_executor"))]
|
||||
type ExecutorInner<'a> = edge_executor::Executor<'a, 64>;
|
||||
#[cfg(not(feature = "async_executor"))]
|
||||
type ExecutorInner<'a> = crate::edge_executor::Executor<'a, 64>;
|
||||
|
||||
#[cfg(all(not(feature = "async_executor"), feature = "edge_executor"))]
|
||||
type LocalExecutorInner<'a> = edge_executor::LocalExecutor<'a, 64>;
|
||||
#[cfg(not(feature = "async_executor"))]
|
||||
type LocalExecutorInner<'a> = crate::edge_executor::LocalExecutor<'a, 64>;
|
||||
|
||||
/// Wrapper around a multi-threading-aware async executor.
|
||||
/// Spawning will generally require tasks to be `Send` and `Sync` to allow multiple
|
||||
|
@ -11,9 +11,6 @@ extern crate std;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(not(any(feature = "async_executor", feature = "edge_executor")))]
|
||||
compile_error!("Either of the `async_executor` or the `edge_executor` features must be enabled.");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod conditional_send {
|
||||
/// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm),
|
||||
@ -43,7 +40,9 @@ pub type BoxedFuture<'a, T> = core::pin::Pin<Box<dyn ConditionalSendFuture<Outpu
|
||||
|
||||
pub mod futures;
|
||||
|
||||
#[cfg(any(feature = "async_executor", feature = "edge_executor"))]
|
||||
#[cfg(not(feature = "async_executor"))]
|
||||
mod edge_executor;
|
||||
|
||||
mod executor;
|
||||
|
||||
mod slice;
|
||||
|
@ -10,50 +10,12 @@ use std::thread_local;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use bevy_platform_support::sync::{Mutex, PoisonError};
|
||||
|
||||
#[cfg(all(
|
||||
feature = "std",
|
||||
any(feature = "async_executor", feature = "edge_executor")
|
||||
))]
|
||||
#[cfg(feature = "std")]
|
||||
use crate::executor::LocalExecutor;
|
||||
|
||||
#[cfg(all(
|
||||
not(feature = "std"),
|
||||
any(feature = "async_executor", feature = "edge_executor")
|
||||
))]
|
||||
#[cfg(not(feature = "std"))]
|
||||
use crate::executor::Executor as LocalExecutor;
|
||||
|
||||
#[cfg(not(any(feature = "async_executor", feature = "edge_executor")))]
|
||||
mod dummy_executor {
|
||||
use async_task::Task;
|
||||
use core::{future::Future, marker::PhantomData};
|
||||
|
||||
/// Dummy implementation of a `LocalExecutor` to allow for a cleaner compiler error
|
||||
/// due to missing feature flags.
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub struct LocalExecutor<'a>(PhantomData<fn(&'a ())>);
|
||||
|
||||
impl<'a> LocalExecutor<'a> {
|
||||
/// Dummy implementation
|
||||
pub const fn new() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
|
||||
/// Dummy implementation
|
||||
pub fn try_tick(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Dummy implementation
|
||||
pub fn spawn<T: 'a>(&self, _: impl Future<Output = T> + 'a) -> Task<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "async_executor", feature = "edge_executor")))]
|
||||
use dummy_executor::LocalExecutor;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
thread_local! {
|
||||
static LOCAL_EXECUTOR: LocalExecutor<'static> = const { LocalExecutor::new() };
|
||||
|
@ -21,9 +21,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
|
||||
bevy_sprite = { path = "../bevy_sprite", version = "0.16.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
|
@ -54,9 +54,7 @@ critical-section = [
|
||||
# bevy
|
||||
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_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false }
|
||||
|
||||
# other
|
||||
|
@ -15,7 +15,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = fa
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev", default-features = false }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
serde = { version = "1", default-features = false, features = [
|
||||
"derive",
|
||||
@ -59,16 +59,7 @@ bevy_reflect = [
|
||||
|
||||
## Uses `async-executor` as a task execution backend.
|
||||
## This backend is incompatible with `no_std` targets.
|
||||
async_executor = [
|
||||
"std",
|
||||
"dep:bevy_tasks",
|
||||
"dep:bevy_utils",
|
||||
"bevy_tasks/async_executor",
|
||||
]
|
||||
|
||||
## Uses `edge-executor` as a task execution backend.
|
||||
## Use this instead of `async-executor` if working on a `no_std` target.
|
||||
edge_executor = ["dep:bevy_tasks", "bevy_tasks/edge_executor"]
|
||||
async_executor = ["std", "dep:bevy_utils", "bevy_tasks/async_executor"]
|
||||
|
||||
# Platform Compatibility
|
||||
|
||||
@ -82,7 +73,7 @@ std = [
|
||||
"bevy_ecs?/std",
|
||||
"bevy_math/std",
|
||||
"bevy_reflect?/std",
|
||||
"bevy_tasks?/std",
|
||||
"bevy_tasks/std",
|
||||
"bevy_utils?/std",
|
||||
"serde?/std",
|
||||
]
|
||||
@ -92,7 +83,7 @@ std = [
|
||||
critical-section = [
|
||||
"bevy_app?/critical-section",
|
||||
"bevy_ecs?/critical-section",
|
||||
"bevy_tasks?/critical-section",
|
||||
"bevy_tasks/critical-section",
|
||||
"bevy_reflect?/critical-section",
|
||||
]
|
||||
|
||||
|
@ -20,9 +20,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||
bevy_input = { path = "../bevy_input", version = "0.16.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
|
||||
bevy_sprite = { path = "../bevy_sprite", version = "0.16.0-dev" }
|
||||
bevy_text = { path = "../bevy_text", version = "0.16.0-dev" }
|
||||
|
@ -14,6 +14,7 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|android-game-activity|Android GameActivity support. Default, choose between this and `android-native-activity`.|
|
||||
|android_shared_stdcxx|Enable using a shared stdlib for cxx on Android|
|
||||
|animation|Enable animation support, and glTF animation loading|
|
||||
|async_executor|Uses `async-executor` as a task execution backend.|
|
||||
|bevy_animation|Provides animation functionality|
|
||||
|bevy_asset|Provides asset functionality|
|
||||
|bevy_audio|Provides audio functionality|
|
||||
@ -22,6 +23,8 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|bevy_gilrs|Adds gamepad support|
|
||||
|bevy_gizmos|Adds support for rendering gizmos|
|
||||
|bevy_gltf|[glTF](https://www.khronos.org/gltf/) support|
|
||||
|bevy_input_focus|Enable input focus subsystem|
|
||||
|bevy_log|Enable integration with `tracing` and `log`|
|
||||
|bevy_mesh_picking_backend|Provides an implementation for picking meshes|
|
||||
|bevy_pbr|Adds PBR rendering|
|
||||
|bevy_picking|Provides picking functionality|
|
||||
@ -42,6 +45,7 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|multi_threaded|Enables multithreaded parallelism in the engine. Disabling it forces all engine tasks to run on a single thread.|
|
||||
|png|PNG image format support|
|
||||
|smaa_luts|Include SMAA Look Up Tables KTX2 Files|
|
||||
|std|Allows access to the `std` crate.|
|
||||
|sysinfo_plugin|Enables system information diagnostic plugin|
|
||||
|tonemapping_luts|Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method for your `Camera2d` or `Camera3d`.|
|
||||
|vorbis|OGG/VORBIS audio format support|
|
||||
@ -65,8 +69,10 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|bevy_remote|Enable the Bevy Remote Protocol|
|
||||
|bevy_ui_debug|Provides a debug overlay for bevy UI|
|
||||
|bmp|BMP image format support|
|
||||
|critical-section|`critical-section` provides the building blocks for synchronization primitives on all platforms, including `no_std`.|
|
||||
|dds|DDS compressed texture support|
|
||||
|debug_glam_assert|Enable assertions in debug builds to check the validity of parameters passed to glam|
|
||||
|default_no_std|Recommended defaults for no_std applications|
|
||||
|detailed_trace|Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in|
|
||||
|dynamic_linking|Force dynamic linking, which improves iterative compile times|
|
||||
|embedded_watcher|Enables watching in memory asset providers for Bevy Asset hot-reloading|
|
||||
@ -80,6 +86,7 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|glam_assert|Enable assertions to check the validity of parameters passed to glam|
|
||||
|ico|ICO image format support|
|
||||
|jpeg|JPEG image format support|
|
||||
|libm|Uses the `libm` maths library instead of the one provided in `std` and `core`.|
|
||||
|meshlet|Enables the meshlet renderer for dense high-poly scenes (experimental)|
|
||||
|meshlet_processor|Enables processing meshes into meshlet meshes for bevy_pbr|
|
||||
|minimp3|MP3 audio format support (through minimp3)|
|
||||
|
@ -44,6 +44,7 @@
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
||||
)]
|
||||
#![no_std]
|
||||
|
||||
pub use bevy_internal::*;
|
||||
|
||||
|
@ -84,7 +84,6 @@ impl CI {
|
||||
cmds.append(&mut commands::DocCheckCommand::default().prepare(sh, flags));
|
||||
cmds.append(&mut commands::DocTestCommand::default().prepare(sh, flags));
|
||||
cmds.append(&mut commands::CompileCheckCommand::default().prepare(sh, flags));
|
||||
cmds.append(&mut commands::CompileCheckNoStdCommand::default().prepare(sh, flags));
|
||||
cmds.append(&mut commands::CompileFailCommand::default().prepare(sh, flags));
|
||||
cmds.append(&mut commands::BenchCheckCommand::default().prepare(sh, flags));
|
||||
cmds.append(&mut commands::ExampleCheckCommand::default().prepare(sh, flags));
|
||||
@ -113,7 +112,6 @@ enum Commands {
|
||||
DocCheck(commands::DocCheckCommand),
|
||||
DocTest(commands::DocTestCommand),
|
||||
CompileCheck(commands::CompileCheckCommand),
|
||||
CompileCheckNoStd(commands::CompileCheckNoStdCommand),
|
||||
CompileFail(commands::CompileFailCommand),
|
||||
BenchCheck(commands::BenchCheckCommand),
|
||||
ExampleCheck(commands::ExampleCheckCommand),
|
||||
@ -136,7 +134,6 @@ impl Prepare for Commands {
|
||||
Commands::DocCheck(subcommand) => subcommand.prepare(sh, flags),
|
||||
Commands::DocTest(subcommand) => subcommand.prepare(sh, flags),
|
||||
Commands::CompileCheck(subcommand) => subcommand.prepare(sh, flags),
|
||||
Commands::CompileCheckNoStd(subcommand) => subcommand.prepare(sh, flags),
|
||||
Commands::CompileFail(subcommand) => subcommand.prepare(sh, flags),
|
||||
Commands::BenchCheck(subcommand) => subcommand.prepare(sh, flags),
|
||||
Commands::ExampleCheck(subcommand) => subcommand.prepare(sh, flags),
|
||||
|
@ -1,179 +0,0 @@
|
||||
use crate::{Flag, Prepare, PreparedCommand};
|
||||
use argh::FromArgs;
|
||||
use xshell::cmd;
|
||||
|
||||
/// Checks that the project compiles for a `no_std` target.
|
||||
/// Note that this tool will attempt to install the target via rustup.
|
||||
/// This can be skipped by passing the "--skip-install" flag.
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "compile-check-no-std")]
|
||||
pub struct CompileCheckNoStdCommand {
|
||||
/// the target to check against.
|
||||
/// Defaults to "x86_64-unknown-none"
|
||||
#[argh(option, default = "Self::default().target")]
|
||||
target: String,
|
||||
/// skip attempting the installation of the target.
|
||||
#[argh(switch)]
|
||||
skip_install: bool,
|
||||
}
|
||||
|
||||
impl Default for CompileCheckNoStdCommand {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
target: String::from("x86_64-unknown-none"),
|
||||
skip_install: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Prepare for CompileCheckNoStdCommand {
|
||||
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {
|
||||
let target = self.target.as_str();
|
||||
let mut commands = Vec::new();
|
||||
|
||||
if !self.skip_install {
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(sh, "rustup target add {target}"),
|
||||
"Unable to add the required target via rustup, is it spelled correctly?",
|
||||
));
|
||||
}
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_ptr --no-default-features --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_ptr no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_utils --no-default-features --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_utils no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_mikktspace --no-default-features --features libm --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_mikktspace no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_reflect --no-default-features --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_reflect no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_math --no-default-features --features libm --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_math no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_color --no-default-features --features libm --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_color no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_tasks --no-default-features --features edge_executor,critical-section --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_tasks no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_ecs --no-default-features --features edge_executor,critical-section,bevy_debug_stepping,bevy_reflect --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_ecs no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_app --no-default-features --features bevy_reflect --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_app no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
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.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_state --no-default-features --features bevy_reflect,bevy_app --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_state no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_window --no-default-features --features libm,bevy_reflect,serialize --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_window no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_transform --no-default-features --features bevy-support,edge_executor,critical-section,serialize,libm --target {target}"
|
||||
),
|
||||
"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_time no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_input_focus --no-default-features --features libm,serialize,bevy_reflect --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_input_focus no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_a11y --no-default-features --features libm,serialize,bevy_reflect --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_a11y no_std compatibility.",
|
||||
));
|
||||
|
||||
commands.push(PreparedCommand::new::<Self>(
|
||||
cmd!(
|
||||
sh,
|
||||
"cargo check -p bevy_diagnostic --no-default-features --features serialize --target {target}"
|
||||
),
|
||||
"Please fix compiler errors in output above for bevy_diagnostic no_std compatibility.",
|
||||
));
|
||||
|
||||
commands
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ pub use bench_check::*;
|
||||
pub use clippy::*;
|
||||
pub use compile::*;
|
||||
pub use compile_check::*;
|
||||
pub use compile_check_no_std::*;
|
||||
pub use compile_fail::*;
|
||||
pub use doc::*;
|
||||
pub use doc_check::*;
|
||||
@ -20,7 +19,6 @@ mod bench_check;
|
||||
mod clippy;
|
||||
mod compile;
|
||||
mod compile_check;
|
||||
mod compile_check_no_std;
|
||||
mod compile_fail;
|
||||
mod doc;
|
||||
mod doc_check;
|
||||
|
Loading…
Reference in New Issue
Block a user