bevy_async_ecs/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(missing_debug_implementations)]
3#![warn(missing_docs)]
4#![warn(clippy::future_not_send)]
5#![doc = include_str!("../README.md")]
6
7mod command;
8mod entity;
9mod system;
10mod util;
11mod wait_for;
12mod world;
13
14use crate::command::{apply_commands, initialize_command_queue, receive_commands};
15use crate::wait_for::{drive_waiting_for, initialize_waiters};
16use async_channel::Receiver;
17use bevy_app::prelude::*;
18use bevy_ecs::prelude::*;
19
20pub use command::{BoxedCommand, CommandQueueBuilder, CommandQueueSender};
21pub use entity::{AsyncComponent, AsyncEntity};
22pub use system::{AsyncIOSystem, AsyncSystem};
23pub use world::{AsyncEvents, AsyncResource, AsyncWorld};
24
25type CowStr = std::borrow::Cow<'static, str>;
26
27#[inline(never)]
28#[cold]
29#[track_caller]
30fn die<T, E: std::fmt::Debug>(e: E) -> T {
31	panic!("invariant broken: {:?}", e)
32}
33
34async fn recv<T: Send>(receiver: Receiver<T>) -> T {
35	receiver.recv().await.unwrap_or_else(die)
36}
37
38/// Adds asynchronous ECS operations to Bevy `App`s.
39#[derive(Debug)]
40pub struct AsyncEcsPlugin;
41
42impl Plugin for AsyncEcsPlugin {
43	fn build(&self, app: &mut App) {
44		app.add_systems(PreStartup, (initialize_command_queue, initialize_waiters))
45			.add_systems(
46				Last,
47				(receive_commands, apply_commands, ApplyDeferred).chain(),
48			)
49			.add_systems(PostUpdate, (drive_waiting_for, ApplyDeferred).chain());
50	}
51}
52
53#[cfg(test)]
54mod tests {
55	use crate::recv;
56	use pollster::block_on;
57
58	#[test]
59	#[should_panic(expected = "invariant broken: RecvError")]
60	fn die() {
61		let (tx, rx) = async_channel::bounded::<()>(1);
62		tx.close();
63		block_on(recv(rx));
64	}
65
66	#[test]
67	fn no_die() {
68		let (tx, rx) = async_channel::bounded::<u8>(1);
69		tx.try_send(3).unwrap();
70		assert_eq!(3, block_on(recv(rx)));
71	}
72}