shred/
system.rs

1use std::{marker::PhantomData, ops::Deref};
2
3use crate::{ResourceId, World};
4
5/// A trait for accessing read/write multiple resources from a system. This can
6/// be used to create dynamic systems that don't specify what they fetch at
7/// compile-time.
8///
9/// For compile-time system data this will all be done for you using
10/// `StaticAccessor`.
11pub trait Accessor: Sized {
12    /// Tries to create a new instance of this type. This one returns `Some` in
13    /// case there is a default, otherwise the system needs to override
14    /// `System::accessor`.
15    fn try_new() -> Option<Self>;
16
17    /// A list of [`ResourceId`]s the bundle
18    /// needs read access to in order to
19    /// build the target resource bundle.
20    ///
21    /// # Contract
22    ///
23    /// Exactly return the dependencies you're going to `fetch`! Doing otherwise
24    /// *will* cause a panic.
25    ///
26    /// This method is only executed once,
27    /// thus the returned value may never change
28    /// (otherwise it has no effect).
29    ///
30    /// [`ResourceId`]: struct.ResourceId.html
31    fn reads(&self) -> Vec<ResourceId>;
32
33    /// A list of [`ResourceId`]s the bundle
34    /// needs write access to in order to
35    /// build the target resource bundle.
36    ///
37    /// # Contract
38    ///
39    /// Exactly return the dependencies you're going to `fetch`! Doing otherwise
40    /// *will* cause a panic.
41    ///
42    /// This method is only executed once,
43    /// thus the returned value may never change
44    /// (otherwise it has no effect).
45    ///
46    /// [`ResourceId`]: struct.ResourceId.html
47    fn writes(&self) -> Vec<ResourceId>;
48}
49
50impl Accessor for () {
51    fn try_new() -> Option<Self> {
52        None
53    }
54
55    fn reads(&self) -> Vec<ResourceId> {
56        Vec::new()
57    }
58
59    fn writes(&self) -> Vec<ResourceId> {
60        Vec::new()
61    }
62}
63
64impl<T: ?Sized> Accessor for PhantomData<T> {
65    fn try_new() -> Option<Self> {
66        None
67    }
68
69    fn reads(&self) -> Vec<ResourceId> {
70        Vec::new()
71    }
72
73    fn writes(&self) -> Vec<ResourceId> {
74        Vec::new()
75    }
76}
77
78/// Either an `Accessor` of the system `T` or a reference to it.
79pub enum AccessorCow<'a, 'b, T>
80where
81    AccessorTy<'a, T>: 'b,
82    T: System<'a> + ?Sized,
83    'a: 'b,
84{
85    /// A reference to an accessor.
86    Ref(&'b AccessorTy<'a, T>),
87    /// An owned accessor.
88    Owned(AccessorTy<'a, T>),
89}
90
91impl<'a, 'b, T> Deref for AccessorCow<'a, 'b, T>
92where
93    AccessorTy<'a, T>: 'b,
94    T: System<'a> + ?Sized + 'b,
95    'a: 'b,
96{
97    type Target = AccessorTy<'a, T>;
98
99    fn deref(&self) -> &AccessorTy<'a, T> {
100        match self {
101            AccessorCow::Ref(r) => r,
102            AccessorCow::Owned(ref o) => o,
103        }
104    }
105}
106
107type AccessorTy<'a, T> = <<T as System<'a>>::SystemData as DynamicSystemData<'a>>::Accessor;
108
109/// Trait for fetching data and running systems. Automatically implemented for
110/// systems.
111pub trait RunNow<'a> {
112    /// Runs the system now.
113    ///
114    /// # Panics
115    ///
116    /// Panics if the system tries to fetch resources
117    /// which are borrowed in an incompatible way already
118    /// (tries to read from a resource which is already written to or
119    /// tries to write to a resource which is read from).
120    fn run_now(&mut self, world: &'a World);
121
122    /// Sets up `World` for a later call to `run_now`.
123    fn setup(&mut self, world: &mut World);
124
125    /// Performs clean up that requires resources from the `World`.
126    /// This commonly removes components from `world` which depend on external
127    /// resources.
128    #[allow(clippy::boxed_local)]
129    fn dispose(self: Box<Self>, world: &mut World) {
130        let _ = world;
131    }
132}
133
134impl<'a, T> RunNow<'a> for T
135where
136    T: System<'a>,
137{
138    fn run_now(&mut self, world: &'a World) {
139        let data = T::SystemData::fetch(&self.accessor(), world);
140        self.run(data);
141    }
142
143    fn setup(&mut self, world: &mut World) {
144        T::setup(self, world);
145    }
146
147    fn dispose(self: Box<Self>, world: &mut World) {
148        T::dispose(*self, world);
149    }
150}
151
152#[repr(u8)]
153#[allow(missing_docs)]
154#[derive(Clone, Copy, Debug)]
155pub enum RunningTime {
156    VeryShort = 1,
157    Short = 2,
158    Average = 3,
159    Long = 4,
160    VeryLong = 5,
161}
162
163/// A `System`, executed with a set of required [`Resource`]s.
164///
165/// [`Resource`]: trait.Resource.html
166pub trait System<'a> {
167    /// The resource bundle required to execute this system.
168    ///
169    /// You will mostly use a tuple of system data (which also implements
170    /// `SystemData`). You can also create such a resource bundle by simply
171    /// deriving `SystemData` for a struct.
172    ///
173    /// Every `SystemData` is also a `DynamicSystemData`.
174    type SystemData: DynamicSystemData<'a>;
175
176    /// Executes the system with the required system
177    /// data.
178    fn run(&mut self, data: Self::SystemData);
179
180    /// Returns a hint how long the system needs for running.
181    /// This is used to optimize the way they're executed (might
182    /// allow more parallelization).
183    ///
184    /// Defaults to `RunningTime::Average`.
185    fn running_time(&self) -> RunningTime {
186        RunningTime::Average
187    }
188
189    /// Return the accessor from the [`SystemData`].
190    fn accessor<'b>(&'b self) -> AccessorCow<'a, 'b, Self> {
191        AccessorCow::Owned(
192            AccessorTy::<'a, Self>::try_new().expect("Missing implementation for `accessor`"),
193        )
194    }
195
196    /// Sets up the `World` using `Self::SystemData::setup`.
197    fn setup(&mut self, world: &mut World) {
198        <Self::SystemData as DynamicSystemData>::setup(&self.accessor(), world)
199    }
200
201    /// Performs clean up that requires resources from the `World`.
202    /// This commonly removes components from `world` which depend on external
203    /// resources.
204    fn dispose(self, world: &mut World)
205    where
206        Self: Sized,
207    {
208        let _ = world;
209    }
210}
211
212/// A static system data that can specify its dependencies at statically (at
213/// compile-time). Most system data is a `SystemData`, the `DynamicSystemData`
214/// type is only needed for very special setups.
215///
216/// You can derive this using the `#[derive(SystemData)]` macro provided by
217/// `shred-derive`. That is as simple as enabling the `shred-derive` feature.
218///
219/// # Examples
220///
221/// ```rust
222/// use shred::{Read, ResourceId, SystemData, World, Write};
223///
224/// #[derive(Default)]
225/// pub struct Clock;
226/// #[derive(Default)]
227/// pub struct Timer;
228///
229/// // This will implement `SystemData` for `MySystemData`.
230/// // Please note that this will only work if `SystemData`, `World` and `ResourceId` are included.
231/// # #[cfg(feature = "shred-derive")]
232/// #[derive(SystemData)]
233/// pub struct MySystemData<'a> {
234///     pub clock: Read<'a, Clock>,
235///     pub timer: Write<'a, Timer>,
236/// }
237/// #
238/// # // The following is required for the snippet to compile without the `shred-derive` feature.
239/// #
240/// # #[cfg(not(feature = "shred-derive"))]
241/// # struct MySystemData<'a> {
242/// #     pub clock: Read<'a, Clock>,
243/// #     pub timer: Write<'a, Timer>,
244/// # }
245/// #
246/// # #[cfg(not(feature = "shred-derive"))]
247/// # impl<'a> SystemData<'a> for MySystemData<'a> {
248/// #     fn setup(world: &mut World) {
249/// #         Read::<'_, Clock>::setup(world);
250/// #         Write::<'_, Timer>::setup(world);
251/// #     }
252/// #
253/// #     fn fetch(world: &'a World) -> Self {
254/// #         Self {
255/// #             clock: Read::<'_, Clock>::fetch(world),
256/// #             timer: Write::<'_, Timer>::fetch(world),
257/// #         }
258/// #     }
259/// #
260/// #     fn reads() -> Vec<ResourceId> {
261/// #         Read::<'_, Clock>::reads()
262/// #     }
263/// #
264/// #     fn writes() -> Vec<ResourceId> {
265/// #         Write::<'_, Timer>::writes()
266/// #     }
267/// # }
268/// ```
269pub trait SystemData<'a> {
270    /// Sets up the system data for fetching it from the `World`.
271    fn setup(world: &mut World);
272
273    /// Fetches the system data from `World`. Note that this is only specified
274    /// for one concrete lifetime `'a`, you need to implement the
275    /// `SystemData` trait for every possible lifetime.
276    fn fetch(world: &'a World) -> Self;
277
278    /// Returns all read dependencies as fetched from `Self::fetch`.
279    ///
280    /// Please note that returning wrong dependencies can lead to a panic.
281    fn reads() -> Vec<ResourceId>;
282
283    /// Returns all write dependencies as fetched from `Self::fetch`.
284    ///
285    /// Please note that returning wrong dependencies can lead to a panic.
286    fn writes() -> Vec<ResourceId>;
287}
288
289impl<'a, T> DynamicSystemData<'a> for T
290where
291    T: SystemData<'a>,
292{
293    type Accessor = StaticAccessor<T>;
294
295    fn setup(_: &StaticAccessor<T>, world: &mut World) {
296        T::setup(world);
297    }
298
299    fn fetch(_: &StaticAccessor<T>, world: &'a World) -> Self {
300        T::fetch(world)
301    }
302}
303
304impl<'a> SystemData<'a> for () {
305    fn setup(_: &mut World) {}
306
307    fn fetch(_: &'a World) -> Self {}
308
309    fn reads() -> Vec<ResourceId> {
310        Vec::new()
311    }
312
313    fn writes() -> Vec<ResourceId> {
314        Vec::new()
315    }
316}
317
318/// The static accessor that is used for `SystemData`.
319#[derive(Default)]
320pub struct StaticAccessor<T> {
321    marker: PhantomData<fn() -> T>,
322}
323
324impl<'a, T> Accessor for StaticAccessor<T>
325where
326    T: SystemData<'a>,
327{
328    fn try_new() -> Option<Self> {
329        Some(StaticAccessor {
330            marker: PhantomData,
331        })
332    }
333
334    fn reads(&self) -> Vec<ResourceId> {
335        T::reads()
336    }
337
338    fn writes(&self) -> Vec<ResourceId> {
339        T::writes()
340    }
341}
342
343/// A struct implementing system data indicates that it bundles some resources
344/// which are required for the execution.
345///
346/// This is the more flexible, but complex variant of `SystemData`.
347pub trait DynamicSystemData<'a> {
348    /// The accessor of the `SystemData`, which specifies the read and write
349    /// dependencies and does the fetching.
350    type Accessor: Accessor;
351
352    /// Sets up `World` for fetching this system data.
353    fn setup(accessor: &Self::Accessor, world: &mut World);
354
355    /// Creates a new resource bundle
356    /// by fetching the required resources
357    /// from the [`World`] struct.
358    ///
359    /// # Contract
360    ///
361    /// Only fetch the resources you returned from `reads` / `writes`!
362    ///
363    /// # Panics
364    ///
365    /// This function may panic if the above contract is violated.
366    /// This function may panic if the resource doesn't exist. This is only the
367    /// case if either `setup` was not called or it didn't insert any
368    /// fallback value.
369    ///
370    /// [`World`]: trait.World.html
371    fn fetch(access: &Self::Accessor, world: &'a World) -> Self;
372}
373
374impl<'a, T: ?Sized> SystemData<'a> for PhantomData<T> {
375    fn setup(_: &mut World) {}
376
377    fn fetch(_: &World) -> Self {
378        PhantomData
379    }
380
381    fn reads() -> Vec<ResourceId> {
382        vec![]
383    }
384
385    fn writes() -> Vec<ResourceId> {
386        vec![]
387    }
388}
389
390macro_rules! impl_data {
391    ( $($ty:ident),* ) => {
392        impl<'a, $($ty),*> SystemData<'a> for ( $( $ty , )* )
393            where $( $ty : SystemData<'a> ),*
394            {
395                fn setup(world: &mut World) {
396                    #![allow(unused_variables)]
397
398                    $(
399                        <$ty as SystemData>::setup(&mut *world);
400                     )*
401                }
402
403                fn fetch(world: &'a World) -> Self {
404                    #![allow(unused_variables)]
405
406                    ( $( <$ty as SystemData<'a>>::fetch(world), )* )
407                }
408
409                fn reads() -> Vec<ResourceId> {
410                    #![allow(unused_mut)]
411
412                    let mut r = Vec::new();
413
414                    $( {
415                        let mut reads = <$ty as SystemData>::reads();
416                        r.append(&mut reads);
417                    } )*
418
419                    r
420                }
421
422                fn writes() -> Vec<ResourceId> {
423                    #![allow(unused_mut)]
424
425                    let mut r = Vec::new();
426
427                    $( {
428                        let mut writes = <$ty as SystemData>::writes();
429                        r.append(&mut writes);
430                    } )*
431
432                    r
433                }
434            }
435    };
436}
437
438mod impl_data {
439    #![cfg_attr(rustfmt, rustfmt_skip)]
440
441    use super::*;
442
443    impl_data!(A);
444    impl_data!(A, B);
445    impl_data!(A, B, C);
446    impl_data!(A, B, C, D);
447    impl_data!(A, B, C, D, E);
448    impl_data!(A, B, C, D, E, F);
449    impl_data!(A, B, C, D, E, F, G);
450    impl_data!(A, B, C, D, E, F, G, H);
451    impl_data!(A, B, C, D, E, F, G, H, I);
452    impl_data!(A, B, C, D, E, F, G, H, I, J);
453    impl_data!(A, B, C, D, E, F, G, H, I, J, K);
454    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L);
455    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M);
456    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
457    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
458    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
459    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
460    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
461    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
462    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
463    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
464    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
465    impl_data!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
466    impl_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);
467    impl_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);
468    impl_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);
469}