specs_visitor/
lib.rs

1//! Utilities for visiting specs components and resources very efficiently.
2//!
3//! This can be used to implement generic transformations of ECS graphs that compile down to very
4//! effective code.
5//!
6//! Use the [`specs-visitor-derive`](https://crates.io/crates/specs-visitor-derive) crate to
7//! automatically derive the traits in this crate.
8#![deny(nonstandard_style, warnings, unused)]
9#![deny(
10    missing_docs,
11    missing_debug_implementations,
12    missing_copy_implementations,
13    trivial_casts,
14    trivial_numeric_casts,
15    unstable_features,
16    unused_import_braces,
17    unused_qualifications
18)]
19#![cfg_attr(feature = "cargo-clippy", deny(clippy::all, clippy::pedantic))]
20
21use std::collections;
22use std::hash;
23use std::sync;
24
25use rayon::prelude::*;
26
27/// Support for generically visiting all `specs` entities of a type with a
28/// visitor.
29///
30/// This trait can be derived automatically with `#[derive(VisitEntities)]` using the
31/// [`specs-visitor-derive`](https://crates.io/crates/specs-visitor-derive) crate.
32pub trait VisitEntities {
33    /// Accepts the given visitor.
34    ///
35    /// The visitor's `visit_entity` method will be called for every entity contained within this
36    /// type.  The visitor could potentially be called in parallel.
37    fn accept<V>(&self, visitor: &V)
38    where
39        V: EntityVisitor;
40}
41
42/// Support for generically mutably visiting all `specs` entities of a type with a
43/// visitor.
44///
45/// This trait can be derived automatically with `#[derive(VisitEntitiesMut)]` using the
46/// [`specs-visitor-derive`](https://crates.io/crates/specs-visitor-derive) crate.
47pub trait VisitEntitiesMut {
48    /// Accepts the given visitor.
49    ///
50    /// The visitor's `visit_entity_mut` method will be called for every entity contained within
51    /// this type.  This gives the visitor mutable references to each entity, allowing them to be
52    /// changed.  Note that the visitor itself has a shared borrow instead of a mutable borrow,
53    /// because it might potentially be called in parallel.
54    fn accept_mut<V>(&mut self, visitor: &V)
55    where
56        V: EntityVisitorMut;
57}
58
59/// A visitor for visiting entities in a read-only fashion.
60///
61/// Types implementing this trait are compatible with the `accept` method on the `VisitEntities`
62/// trait.
63pub trait EntityVisitor: Send + Sync {
64    /// Allows the visitor to visit the specified entity.
65    ///
66    /// This method could potentially be called in parallel.
67    fn visit_entity(&self, entity: specs::Entity);
68}
69
70/// A visitor for visiting entities mutably.
71///
72/// Types implementing this trait are compatible with the `accept_mut` method on the
73/// `VisitEntitiesMut` trait.
74pub trait EntityVisitorMut: Send + Sync {
75    /// Allows the visitor to visit the specified entity mutably.
76    ///
77    /// This method could potentially be called in parallel.
78    fn visit_entity_mut(&self, entity: &mut specs::Entity);
79}
80
81impl VisitEntities for specs::Entity {
82    fn accept<V>(&self, visitor: &V)
83    where
84        V: EntityVisitor,
85    {
86        visitor.visit_entity(*self)
87    }
88}
89
90impl VisitEntitiesMut for specs::Entity {
91    fn accept_mut<V>(&mut self, visitor: &V)
92    where
93        V: EntityVisitorMut,
94    {
95        visitor.visit_entity_mut(self)
96    }
97}
98
99impl<A> VisitEntities for Option<A>
100where
101    A: VisitEntities + Send + Sync,
102{
103    fn accept<V>(&self, visitor: &V)
104    where
105        V: EntityVisitor,
106    {
107        self.par_iter().for_each(|element| element.accept(visitor))
108    }
109}
110
111impl<A> VisitEntitiesMut for Option<A>
112where
113    A: VisitEntitiesMut + Send + Sync,
114{
115    fn accept_mut<V>(&mut self, visitor: &V)
116    where
117        V: EntityVisitorMut,
118    {
119        self.par_iter_mut()
120            .for_each(|element| element.accept_mut(visitor))
121    }
122}
123
124impl<A> VisitEntities for Vec<A>
125where
126    A: VisitEntities + Send + Sync,
127{
128    fn accept<V>(&self, visitor: &V)
129    where
130        V: EntityVisitor,
131    {
132        self.par_iter().for_each(|element| element.accept(visitor))
133    }
134}
135
136impl<A> VisitEntitiesMut for Vec<A>
137where
138    A: VisitEntitiesMut + Send + Sync,
139{
140    fn accept_mut<V>(&mut self, visitor: &V)
141    where
142        V: EntityVisitorMut,
143    {
144        self.par_iter_mut()
145            .for_each(|element| element.accept_mut(visitor))
146    }
147}
148
149impl<A> VisitEntities for Box<A>
150where
151    A: VisitEntities + Send + Sync,
152{
153    fn accept<V>(&self, visitor: &V)
154    where
155        V: EntityVisitor,
156    {
157        (**self).accept(visitor)
158    }
159}
160
161impl<A> VisitEntitiesMut for Box<A>
162where
163    A: VisitEntitiesMut + Send + Sync,
164{
165    fn accept_mut<V>(&mut self, visitor: &V)
166    where
167        V: EntityVisitorMut,
168    {
169        (**self).accept_mut(visitor)
170    }
171}
172
173impl<A, B> VisitEntities for collections::HashMap<A, B>
174where
175    A: Eq + hash::Hash + Send + Sync,
176    B: VisitEntities + Send + Sync,
177{
178    fn accept<V>(&self, visitor: &V)
179    where
180        V: EntityVisitor,
181    {
182        self.par_iter()
183            .for_each(|(_, element)| element.accept(visitor))
184    }
185}
186
187impl<A, B> VisitEntitiesMut for collections::HashMap<A, B>
188where
189    A: Eq + hash::Hash + Send + Sync,
190    B: VisitEntitiesMut + Send + Sync,
191{
192    fn accept_mut<V>(&mut self, visitor: &V)
193    where
194        V: EntityVisitorMut,
195    {
196        self.par_iter_mut()
197            .for_each(|(_, element)| element.accept_mut(visitor))
198    }
199}
200
201impl<A> VisitEntities for sync::Arc<A>
202where
203    A: VisitEntities,
204{
205    fn accept<V>(&self, visitor: &V)
206    where
207        V: EntityVisitor,
208    {
209        (**self).accept(visitor)
210    }
211}
212
213macro_rules! impl_visit_entities_empty {
214    ($t:ty) => {
215        impl VisitEntities for $t {
216            #[inline(always)]
217            fn accept<V>(&self, _visitor: &V)
218            where
219                V: EntityVisitor,
220            {
221            }
222        }
223
224        impl VisitEntitiesMut for $t {
225            #[inline(always)]
226            fn accept_mut<V>(&mut self, _visitor: &V)
227            where
228                V: EntityVisitorMut,
229            {
230            }
231        }
232    };
233}
234
235impl_visit_entities_empty!(i8);
236impl_visit_entities_empty!(i16);
237impl_visit_entities_empty!(i32);
238impl_visit_entities_empty!(i64);
239impl_visit_entities_empty!(isize);
240impl_visit_entities_empty!(u8);
241impl_visit_entities_empty!(u16);
242impl_visit_entities_empty!(u32);
243impl_visit_entities_empty!(u64);
244impl_visit_entities_empty!(usize);
245impl_visit_entities_empty!(f32);
246impl_visit_entities_empty!(f64);
247impl_visit_entities_empty!(bool);
248impl_visit_entities_empty!(char);
249
250impl_visit_entities_empty!(String);