bevy_tasks/
executor.rs

1//! Provides a fundamental executor primitive appropriate for the target platform
2//! and feature set selected.
3//! By default, the `async_executor` feature will be enabled, which will rely on
4//! [`async-executor`] for the underlying implementation. This requires `std`,
5//! so is not suitable for `no_std` contexts. Instead, you must use `edge_executor`,
6//! which relies on the alternate [`edge-executor`] backend.
7//!
8//! [`async-executor`]: https://crates.io/crates/async-executor
9//! [`edge-executor`]: https://crates.io/crates/edge-executor
10
11use core::{
12    fmt,
13    panic::{RefUnwindSafe, UnwindSafe},
14};
15use derive_more::{Deref, DerefMut};
16
17crate::cfg::async_executor! {
18    if {
19        type ExecutorInner<'a> = async_executor::Executor<'a>;
20        type LocalExecutorInner<'a> = async_executor::LocalExecutor<'a>;
21    } else {
22        type ExecutorInner<'a> = crate::edge_executor::Executor<'a, 64>;
23        type LocalExecutorInner<'a> = crate::edge_executor::LocalExecutor<'a, 64>;
24    }
25}
26
27crate::cfg::multi_threaded! {
28    pub use async_task::FallibleTask;
29}
30
31/// Wrapper around a multi-threading-aware async executor.
32/// Spawning will generally require tasks to be `Send` and `Sync` to allow multiple
33/// threads to send/receive/advance tasks.
34///
35/// If you require an executor _without_ the `Send` and `Sync` requirements, consider
36/// using [`LocalExecutor`] instead.
37#[derive(Deref, DerefMut, Default)]
38pub struct Executor<'a>(ExecutorInner<'a>);
39
40/// Wrapper around a single-threaded async executor.
41/// Spawning wont generally require tasks to be `Send` and `Sync`, at the cost of
42/// this executor itself not being `Send` or `Sync`. This makes it unsuitable for
43/// global statics.
44///
45/// If need to store an executor in a global static, or send across threads,
46/// consider using [`Executor`] instead.
47#[derive(Deref, DerefMut, Default)]
48pub struct LocalExecutor<'a>(LocalExecutorInner<'a>);
49
50impl Executor<'_> {
51    /// Construct a new [`Executor`]
52    #[expect(clippy::allow_attributes, reason = "This lint may not always trigger.")]
53    #[allow(dead_code, reason = "not all feature flags require this function")]
54    pub const fn new() -> Self {
55        Self(ExecutorInner::new())
56    }
57}
58
59impl LocalExecutor<'_> {
60    /// Construct a new [`LocalExecutor`]
61    #[expect(clippy::allow_attributes, reason = "This lint may not always trigger.")]
62    #[allow(dead_code, reason = "not all feature flags require this function")]
63    pub const fn new() -> Self {
64        Self(LocalExecutorInner::new())
65    }
66}
67
68impl UnwindSafe for Executor<'_> {}
69
70impl RefUnwindSafe for Executor<'_> {}
71
72impl UnwindSafe for LocalExecutor<'_> {}
73
74impl RefUnwindSafe for LocalExecutor<'_> {}
75
76impl fmt::Debug for Executor<'_> {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        f.debug_struct("Executor").finish()
79    }
80}
81
82impl fmt::Debug for LocalExecutor<'_> {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        f.debug_struct("LocalExecutor").finish()
85    }
86}