async_ecs/system/system_data.rs
1use std::marker::PhantomData;
2
3use crate::{
4 access::{Accessor, StaticAccessor},
5 resource::ResourceId,
6 world::World,
7};
8
9/// A static system data that can specify its dependencies at statically (at
10/// compile-time). Most system data is a `SystemData`, the `DynamicSystemData`
11/// type is only needed for very special setups.
12///
13/// You can derive this using the `#[derive(SystemData)]` macro provided by
14/// `async-ecs-derive`. That is as simple as enabling the `derive` feature.
15///
16/// # Examples
17///
18/// ```rust
19/// use async_ecs::{Read, ResourceId, SystemData, World, Write};
20///
21/// #[derive(Default)]
22/// pub struct Clock;
23/// #[derive(Default)]
24/// pub struct Timer;
25///
26/// // This will implement `SystemData` for `MySystemData`.
27/// // Please note that this will only work if `SystemData`, `World` and `ResourceId` are included.
28/// # #[cfg(feature = "derive")]
29/// #[derive(SystemData)]
30/// pub struct MySystemData<'a> {
31/// pub clock: Read<'a, Clock>,
32/// pub timer: Write<'a, Timer>,
33/// }
34/// #
35/// # // The following is required for the snippet to compile without the `derive` feature.
36/// #
37/// # #[cfg(not(feature = "derive"))]
38/// # struct MySystemData<'a> {
39/// # pub clock: Read<'a, Clock>,
40/// # pub timer: Write<'a, Timer>,
41/// # }
42/// #
43/// # #[cfg(not(feature = "derive"))]
44/// # impl<'a> SystemData<'a> for MySystemData<'a> {
45/// # fn setup(world: &mut World) {
46/// # Read::<'_, Clock>::setup(world);
47/// # Write::<'_, Timer>::setup(world);
48/// # }
49/// #
50/// # fn fetch(world: &'a World) -> Self {
51/// # Self {
52/// # clock: Read::<'_, Clock>::fetch(world),
53/// # timer: Write::<'_, Timer>::fetch(world),
54/// # }
55/// # }
56/// #
57/// # fn reads() -> Vec<ResourceId> {
58/// # Read::<'_, Clock>::reads()
59/// # }
60/// #
61/// # fn writes() -> Vec<ResourceId> {
62/// # Write::<'_, Timer>::writes()
63/// # }
64/// # }
65/// ```
66pub trait SystemData<'a> {
67 /// Sets up the system data for fetching it from the `World`.
68 fn setup(world: &mut World);
69
70 /// Fetches the system data from `World`. Note that this is only specified
71 /// for one concrete lifetime `'a`, you need to implement the
72 /// `SystemData` trait for every possible lifetime.
73 fn fetch(world: &'a World) -> Self;
74
75 /// Returns all read dependencies as fetched from `Self::fetch`.
76 ///
77 /// Please note that returning wrong dependencies can lead to a panic.
78 fn reads() -> Vec<ResourceId>;
79
80 /// Returns all write dependencies as fetched from `Self::fetch`.
81 ///
82 /// Please note that returning wrong dependencies can lead to a panic.
83 fn writes() -> Vec<ResourceId>;
84}
85
86/// A struct implementing system data indicates that it bundles some resources
87/// which are required for the execution.
88///
89/// This is the more flexible, but complex variant of `SystemData`.
90pub trait DynamicSystemData<'a> {
91 /// The accessor of the `SystemData`, which specifies the read and write
92 /// dependencies and does the fetching.
93 type Accessor: Accessor;
94
95 /// Sets up `World` for fetching this system data.
96 fn setup(accessor: &Self::Accessor, world: &mut World);
97
98 /// Creates a new resource bundle
99 /// by fetching the required resources
100 /// from the [`World`] struct.
101 ///
102 /// # Contract
103 ///
104 /// Only fetch the resources you returned from `reads` / `writes`!
105 ///
106 /// # Panics
107 ///
108 /// This function may panic if the above contract is violated.
109 /// This function may panic if the resource doesn't exist. This is only the
110 /// case if either `setup` was not called or it didn't insert any
111 /// fallback value.
112 ///
113 /// [`World`]: trait.World.html
114 fn fetch(access: &Self::Accessor, world: &'a World) -> Self;
115}
116
117/* SystemData */
118
119impl<'a, T> SystemData<'a> for PhantomData<T>
120where
121 T: ?Sized,
122{
123 fn setup(_: &mut World) {}
124
125 fn fetch(_: &World) -> Self {
126 PhantomData
127 }
128
129 fn reads() -> Vec<ResourceId> {
130 vec![]
131 }
132
133 fn writes() -> Vec<ResourceId> {
134 vec![]
135 }
136}
137
138/* DynamicSystemData */
139
140impl<'a, T> DynamicSystemData<'a> for T
141where
142 T: SystemData<'a>,
143{
144 type Accessor = StaticAccessor<T>;
145
146 fn setup(_: &StaticAccessor<T>, world: &mut World) {
147 T::setup(world);
148 }
149
150 fn fetch(_: &StaticAccessor<T>, world: &'a World) -> Self {
151 T::fetch(world)
152 }
153}
154
155mod impl_system_data {
156 use super::*;
157
158 macro_rules! impl_system_data {
159 ( $($ty:ident),* ) => {
160 impl<'a, $($ty),*> SystemData<'a> for ( $( $ty , )* )
161 where $( $ty : SystemData<'a> ),*
162 {
163 fn setup(world: &mut World) {
164 #![allow(unused_variables)]
165
166 $(
167 <$ty as SystemData>::setup(&mut *world);
168 )*
169 }
170
171 fn fetch(world: &'a World) -> Self {
172 #![allow(unused_variables)]
173
174 ( $( <$ty as SystemData<'a>>::fetch(world), )* )
175 }
176
177 fn reads() -> Vec<ResourceId> {
178 #![allow(unused_mut)]
179
180 let mut r = Vec::new();
181
182 $( {
183 let mut reads = <$ty as SystemData>::reads();
184 r.append(&mut reads);
185 } )*
186
187 r
188 }
189
190 fn writes() -> Vec<ResourceId> {
191 #![allow(unused_mut)]
192
193 let mut r = Vec::new();
194
195 $( {
196 let mut writes = <$ty as SystemData>::writes();
197 r.append(&mut writes);
198 } )*
199
200 r
201 }
202 }
203 };
204 }
205
206 impl_system_data!(A);
207 impl_system_data!(A, B);
208 impl_system_data!(A, B, C);
209 impl_system_data!(A, B, C, D);
210 impl_system_data!(A, B, C, D, E);
211 impl_system_data!(A, B, C, D, E, F);
212 impl_system_data!(A, B, C, D, E, F, G);
213 impl_system_data!(A, B, C, D, E, F, G, H);
214 impl_system_data!(A, B, C, D, E, F, G, H, I);
215 impl_system_data!(A, B, C, D, E, F, G, H, I, J);
216 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K);
217 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L);
218 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M);
219 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
220 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
221 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
222 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
223 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
224 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
225 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
226 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
227 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
228 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
229 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
230 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
231 impl_system_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
232}