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
8extern crate alloc;
11
12mod name;
13#[cfg(feature = "serialize")]
14mod serde;
15mod task_pool_options;
16
17use bevy_ecs::system::Resource;
18pub use name::*;
19pub use task_pool_options::*;
20
21pub mod prelude {
25 #[doc(hidden)]
26 pub use crate::{
27 FrameCountPlugin, Name, NameOrEntity, TaskPoolOptions, TaskPoolPlugin,
28 TypeRegistrationPlugin,
29 };
30}
31
32use bevy_app::prelude::*;
33use bevy_ecs::prelude::*;
34use core::marker::PhantomData;
35
36#[cfg(not(target_arch = "wasm32"))]
37use bevy_tasks::tick_global_task_pools_on_main_thread;
38
39#[derive(Default)]
41pub struct TypeRegistrationPlugin;
42
43impl Plugin for TypeRegistrationPlugin {
44 #[cfg_attr(not(feature = "bevy_reflect"), allow(unused_variables))]
45 fn build(&self, app: &mut App) {
46 #[cfg(feature = "bevy_reflect")]
47 app.register_type::<Name>();
48 }
49}
50
51#[derive(Default)]
54pub struct TaskPoolPlugin {
55 pub task_pool_options: TaskPoolOptions,
57}
58
59impl Plugin for TaskPoolPlugin {
60 fn build(&self, _app: &mut App) {
61 self.task_pool_options.create_default_pools();
63
64 #[cfg(not(target_arch = "wasm32"))]
65 _app.add_systems(Last, tick_global_task_pools);
66 }
67}
68pub struct NonSendMarker(PhantomData<*mut ()>);
70
71#[cfg(not(target_arch = "wasm32"))]
76fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
77 tick_global_task_pools_on_main_thread();
78}
79
80#[derive(Debug, Default, Resource, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
91pub struct FrameCount(pub u32);
92
93#[derive(Default)]
95pub struct FrameCountPlugin;
96
97impl Plugin for FrameCountPlugin {
98 fn build(&self, app: &mut App) {
99 app.init_resource::<FrameCount>();
100 app.add_systems(Last, update_frame_count);
101 }
102}
103
104pub fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
108 frame_count.0 = frame_count.0.wrapping_add(1);
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use bevy_tasks::prelude::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
115
116 #[test]
117 fn runs_spawn_local_tasks() {
118 let mut app = App::new();
119 app.add_plugins((TaskPoolPlugin::default(), TypeRegistrationPlugin));
120
121 let (async_tx, async_rx) = crossbeam_channel::unbounded();
122 AsyncComputeTaskPool::get()
123 .spawn_local(async move {
124 async_tx.send(()).unwrap();
125 })
126 .detach();
127
128 let (compute_tx, compute_rx) = crossbeam_channel::unbounded();
129 ComputeTaskPool::get()
130 .spawn_local(async move {
131 compute_tx.send(()).unwrap();
132 })
133 .detach();
134
135 let (io_tx, io_rx) = crossbeam_channel::unbounded();
136 IoTaskPool::get()
137 .spawn_local(async move {
138 io_tx.send(()).unwrap();
139 })
140 .detach();
141
142 app.run();
143
144 async_rx.try_recv().unwrap();
145 compute_rx.try_recv().unwrap();
146 io_rx.try_recv().unwrap();
147 }
148
149 #[test]
150 fn frame_counter_update() {
151 let mut app = App::new();
152 app.add_plugins((
153 TaskPoolPlugin::default(),
154 TypeRegistrationPlugin,
155 FrameCountPlugin,
156 ));
157 app.update();
158
159 let frame_count = app.world().resource::<FrameCount>();
160 assert_eq!(1, frame_count.0);
161 }
162}