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