1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![forbid(unsafe_code)]
3#![doc(
4 html_logo_url = "https://bevyengine.org/assets/icon.png",
5 html_favicon_url = "https://bevyengine.org/assets/icon.png"
6)]
7
8mod name;
11#[cfg(feature = "serialize")]
12mod serde;
13mod task_pool_options;
14
15use bevy_ecs::system::Resource;
16pub use name::*;
17pub use task_pool_options::*;
18
19pub mod prelude {
20 #[doc(hidden)]
22 pub use crate::{
23 DebugName, FrameCountPlugin, Name, TaskPoolOptions, TaskPoolPlugin, TypeRegistrationPlugin,
24 };
25}
26
27use bevy_app::prelude::*;
28use bevy_ecs::prelude::*;
29use std::marker::PhantomData;
30
31#[cfg(not(target_arch = "wasm32"))]
32use bevy_tasks::tick_global_task_pools_on_main_thread;
33
34#[derive(Default)]
36pub struct TypeRegistrationPlugin;
37
38impl Plugin for TypeRegistrationPlugin {
39 fn build(&self, app: &mut App) {
40 app.register_type::<Name>();
41 }
42}
43
44#[derive(Default)]
47pub struct TaskPoolPlugin {
48 pub task_pool_options: TaskPoolOptions,
50}
51
52impl Plugin for TaskPoolPlugin {
53 fn build(&self, _app: &mut App) {
54 self.task_pool_options.create_default_pools();
56
57 #[cfg(not(target_arch = "wasm32"))]
58 _app.add_systems(Last, tick_global_task_pools);
59 }
60}
61pub struct NonSendMarker(PhantomData<*mut ()>);
63
64#[cfg(not(target_arch = "wasm32"))]
69fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
70 tick_global_task_pools_on_main_thread();
71}
72
73#[derive(Debug, Default, Resource, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
84pub struct FrameCount(pub u32);
85
86#[derive(Default)]
88pub struct FrameCountPlugin;
89
90impl Plugin for FrameCountPlugin {
91 fn build(&self, app: &mut App) {
92 app.init_resource::<FrameCount>();
93 app.add_systems(Last, update_frame_count);
94 }
95}
96
97pub fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
101 frame_count.0 = frame_count.0.wrapping_add(1);
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use bevy_tasks::prelude::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
108
109 #[test]
110 fn runs_spawn_local_tasks() {
111 let mut app = App::new();
112 app.add_plugins((TaskPoolPlugin::default(), TypeRegistrationPlugin));
113
114 let (async_tx, async_rx) = crossbeam_channel::unbounded();
115 AsyncComputeTaskPool::get()
116 .spawn_local(async move {
117 async_tx.send(()).unwrap();
118 })
119 .detach();
120
121 let (compute_tx, compute_rx) = crossbeam_channel::unbounded();
122 ComputeTaskPool::get()
123 .spawn_local(async move {
124 compute_tx.send(()).unwrap();
125 })
126 .detach();
127
128 let (io_tx, io_rx) = crossbeam_channel::unbounded();
129 IoTaskPool::get()
130 .spawn_local(async move {
131 io_tx.send(()).unwrap();
132 })
133 .detach();
134
135 app.run();
136
137 async_rx.try_recv().unwrap();
138 compute_rx.try_recv().unwrap();
139 io_rx.try_recv().unwrap();
140 }
141
142 #[test]
143 fn frame_counter_update() {
144 let mut app = App::new();
145 app.add_plugins((
146 TaskPoolPlugin::default(),
147 TypeRegistrationPlugin,
148 FrameCountPlugin,
149 ));
150 app.update();
151
152 let frame_count = app.world().resource::<FrameCount>();
153 assert_eq!(1, frame_count.0);
154 }
155}