bevy_tasks/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4    html_logo_url = "https://bevy.org/assets/icon.png",
5    html_favicon_url = "https://bevy.org/assets/icon.png"
6)]
7#![no_std]
8
9/// Configuration information for this crate.
10pub mod cfg {
11    pub(crate) use bevy_platform::cfg::*;
12
13    pub use bevy_platform::cfg::{alloc, std, web};
14
15    define_alias! {
16        #[cfg(feature = "async_executor")] => {
17            /// Indicates `async_executor` is used as the future execution backend.
18            async_executor
19        }
20
21        #[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))] => {
22            /// Indicates multithreading support.
23            multi_threaded
24        }
25
26        #[cfg(target_arch = "wasm32")] => {
27            /// Indicates the current target requires additional `Send` bounds.
28            conditional_send
29        }
30
31        #[cfg(feature = "async-io")] => {
32            /// Indicates `async-io` will be used for the implementation of `block_on`.
33            async_io
34        }
35
36        #[cfg(feature = "futures-lite")] => {
37            /// Indicates `futures-lite` will be used for the implementation of `block_on`.
38            futures_lite
39        }
40    }
41}
42
43cfg::std! {
44    extern crate std;
45}
46
47extern crate alloc;
48
49cfg::conditional_send! {
50    if {
51        /// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm),
52        /// futures aren't Send.
53        pub trait ConditionalSend {}
54        impl<T> ConditionalSend for T {}
55    } else {
56        /// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm),
57        /// futures aren't Send.
58        pub trait ConditionalSend: Send {}
59        impl<T: Send> ConditionalSend for T {}
60    }
61}
62
63/// Use [`ConditionalSendFuture`] for a future with an optional Send trait bound, as on certain platforms (eg. Wasm),
64/// futures aren't Send.
65pub trait ConditionalSendFuture: Future + ConditionalSend {}
66
67impl<T: Future + ConditionalSend> ConditionalSendFuture for T {}
68
69use alloc::boxed::Box;
70
71/// An owned and dynamically typed Future used when you can't statically type your result or need to add some indirection.
72pub type BoxedFuture<'a, T> = core::pin::Pin<Box<dyn ConditionalSendFuture<Output = T> + 'a>>;
73
74// Modules
75mod executor;
76pub mod futures;
77mod iter;
78mod slice;
79mod task;
80mod usages;
81
82cfg::async_executor! {
83    if {} else {
84        mod edge_executor;
85    }
86}
87
88// Exports
89pub use iter::ParallelIterator;
90pub use slice::{ParallelSlice, ParallelSliceMut};
91pub use task::Task;
92pub use usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
93
94pub use futures_lite;
95pub use futures_lite::future::poll_once;
96
97cfg::web! {
98    if {} else {
99        pub use usages::tick_global_task_pools_on_main_thread;
100    }
101}
102
103cfg::multi_threaded! {
104    if {
105        mod task_pool;
106        mod thread_executor;
107
108        pub use task_pool::{Scope, TaskPool, TaskPoolBuilder};
109        pub use thread_executor::{ThreadExecutor, ThreadExecutorTicker};
110    } else {
111        mod single_threaded_task_pool;
112
113        pub use single_threaded_task_pool::{Scope, TaskPool, TaskPoolBuilder, ThreadExecutor};
114    }
115}
116
117cfg::switch! {
118    cfg::async_io => {
119        pub use async_io::block_on;
120    }
121    cfg::futures_lite => {
122        pub use futures_lite::future::block_on;
123    }
124    _ => {
125        /// Blocks on the supplied `future`.
126        /// This implementation will busy-wait until it is completed.
127        /// Consider enabling the `async-io` or `futures-lite` features.
128        pub fn block_on<T>(future: impl Future<Output = T>) -> T {
129            use core::task::{Poll, Context};
130
131            // Pin the future on the stack.
132            let mut future = core::pin::pin!(future);
133
134            // We don't care about the waker as we're just going to poll as fast as possible.
135            let cx = &mut Context::from_waker(core::task::Waker::noop());
136
137            // Keep polling until the future is ready.
138            loop {
139                match future.as_mut().poll(cx) {
140                    Poll::Ready(output) => return output,
141                    Poll::Pending => core::hint::spin_loop(),
142                }
143            }
144        }
145    }
146}
147
148/// The tasks prelude.
149///
150/// This includes the most common types in this crate, re-exported for your convenience.
151pub mod prelude {
152    #[doc(hidden)]
153    pub use crate::{
154        block_on,
155        iter::ParallelIterator,
156        slice::{ParallelSlice, ParallelSliceMut},
157        usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool},
158    };
159}
160
161/// Gets the logical CPU core count available to the current process.
162///
163/// This is identical to `std::thread::available_parallelism`, except
164/// it will return a default value of 1 if it internally errors out.
165///
166/// This will always return at least 1.
167pub fn available_parallelism() -> usize {
168    cfg::switch! {{
169        cfg::std => {
170            std::thread::available_parallelism()
171                .map(core::num::NonZero::<usize>::get)
172                .unwrap_or(1)
173        }
174        _ => {
175            1
176        }
177    }}
178}