specs/storage/data.rs
1use shred::{Fetch, FetchMut, MetaTable, ResourceId, SystemData, World};
2
3use crate::{
4 storage::{AnyStorage, MaskedStorage, Storage, TryDefault},
5 world::{Component, EntitiesRes},
6};
7
8/// A storage with read access.
9///
10/// This is just a type alias for a fetched component storage.
11///
12/// The main functionality it provides is listed in the following,
13/// however make sure to also check out the documentation for the
14/// respective methods on `Storage`.
15///
16/// ## Aliasing
17///
18/// **It is strictly disallowed to get both a `ReadStorage` and a `WriteStorage`
19/// of the same component.**
20/// Because Specs uses interior mutability for its resources, we can't check
21/// this at compile time. If you try to do this, you will get a panic.
22///
23/// It is explicitly allowed to get multiple `ReadStorage`s for the same
24/// component.
25///
26/// ## Joining storages
27///
28/// `&ReadStorage` implements `Join`, which allows to do
29/// something like this:
30///
31/// ```
32/// use specs::prelude::*;
33///
34/// struct Pos;
35/// impl Component for Pos {
36/// type Storage = VecStorage<Self>;
37/// }
38/// struct Vel;
39/// impl Component for Vel {
40/// type Storage = VecStorage<Self>;
41/// }
42///
43/// let mut world = World::new();
44/// world.register::<Pos>();
45/// world.register::<Vel>();
46/// let pos_storage = world.read_storage::<Pos>();
47/// let vel_storage = world.read_storage::<Vel>();
48///
49/// for (pos, vel) in (&pos_storage, &vel_storage).join() {}
50/// ```
51///
52/// This joins the position and the velocity storage, which means it only
53/// iterates over the components of entities that have both a position
54/// **and** a velocity.
55///
56/// ## Retrieving single components
57///
58/// If you have an entity (for example because you stored it before
59/// or because you're joining over `Entities`), you can get a single
60/// component by calling `Storage::get`:
61///
62/// ```
63/// # use specs::prelude::*;
64/// # #[derive(Debug, PartialEq)]
65/// # struct Pos; impl Component for Pos { type Storage = VecStorage<Self>; }
66/// # #[derive(Debug, PartialEq)]
67/// # struct Vel; impl Component for Vel { type Storage = VecStorage<Self>; }
68/// #
69/// # let mut world = World::new(); world.register::<Pos>(); world.register::<Vel>();
70/// let entity1 = world.create_entity().with(Pos).build();
71/// let entity2 = world.create_entity().with(Vel).build();
72///
73/// # let pos_storage = world.read_storage::<Pos>();
74/// # let vel_storage = world.read_storage::<Vel>();
75/// assert_eq!(pos_storage.get(entity1), Some(&Pos));
76/// assert_eq!(pos_storage.get(entity2), None);
77///
78/// assert_eq!(vel_storage.get(entity1), None);
79/// assert_eq!(vel_storage.get(entity2), Some(&Vel));
80/// ```
81///
82/// ## Usage as `SystemData`
83///
84/// `ReadStorage` implements `SystemData` which allows you to
85/// get it inside a system by simply adding it to the tuple:
86///
87/// ```
88/// # use specs::prelude::*;
89/// #[derive(Debug)]
90/// struct Pos {
91/// x: f32,
92/// y: f32,
93/// }
94///
95/// impl Component for Pos {
96/// type Storage = VecStorage<Self>;
97/// }
98///
99/// struct Sys;
100///
101/// impl<'a> System<'a> for Sys {
102/// type SystemData = (Entities<'a>, ReadStorage<'a, Pos>);
103///
104/// fn run(&mut self, (ent, pos): Self::SystemData) {
105/// for (ent, pos) in (&*ent, &pos).join() {
106/// println!("Entitiy with id {} has a position of {:?}", ent.id(), pos);
107/// }
108/// }
109/// }
110/// ```
111///
112/// These operations can't mutate anything; if you want to do
113/// insertions or modify components, you need to use `WriteStorage`.
114/// Note that you can also use `LazyUpdate` , which does insertions on
115/// `World::maintain`. This allows more concurrency and is designed
116/// to be used for entity initialization.
117pub type ReadStorage<'a, T> = Storage<'a, T, Fetch<'a, MaskedStorage<T>>>;
118
119impl<'a, T> SystemData<'a> for ReadStorage<'a, T>
120where
121 T: Component,
122{
123 fn setup(res: &mut World) {
124 res.entry::<MaskedStorage<T>>()
125 .or_insert_with(|| MaskedStorage::new(<T::Storage as TryDefault>::unwrap_default()));
126 res.fetch_mut::<MetaTable<dyn AnyStorage>>()
127 .register::<MaskedStorage<T>>();
128 }
129
130 fn fetch(res: &'a World) -> Self {
131 Storage::new(res.fetch(), res.fetch())
132 }
133
134 fn reads() -> Vec<ResourceId> {
135 vec![
136 ResourceId::new::<EntitiesRes>(),
137 ResourceId::new::<MaskedStorage<T>>(),
138 ]
139 }
140
141 fn writes() -> Vec<ResourceId> {
142 vec![]
143 }
144}
145
146/// A storage with read and write access.
147///
148/// Additionally to what `ReadStorage` can do a storage with mutable access
149/// allows:
150///
151/// ## Aliasing
152///
153/// **It is strictly disallowed to fetch both a `ReadStorage` and a
154/// `WriteStorage` of the same component.**
155/// Because Specs uses interior mutability for its resources, we can't check
156/// this at compile time. If you try to do this, you will get a panic.
157///
158/// It is also disallowed to fetch multiple `WriteStorage`s for the same
159/// component.
160///
161/// ## Retrieve components mutably
162///
163/// This works just like `Storage::get`, but returns a mutable reference:
164///
165/// ```
166/// # use specs::prelude::*;
167/// # #[derive(Debug, PartialEq)]
168/// # struct Pos(f32); impl Component for Pos { type Storage = VecStorage<Self>; }
169/// #
170/// # let mut world = World::new(); world.register::<Pos>();
171/// let entity = world.create_entity().with(Pos(2.0)).build();
172/// # let mut pos_storage = world.write_storage::<Pos>();
173///
174/// assert_eq!(pos_storage.get_mut(entity), Some(&mut Pos(2.0)));
175/// if let Some(pos) = pos_storage.get_mut(entity) {
176/// *pos = Pos(4.5);
177/// }
178///
179/// assert_eq!(pos_storage.get(entity), Some(&Pos(4.5)));
180/// ```
181///
182/// ## Inserting and removing components
183///
184/// You can insert components using `Storage::insert` and remove them
185/// again with `Storage::remove`.
186///
187/// ```
188/// # use specs::prelude::*;
189/// # use specs::storage::InsertResult;
190/// # #[derive(Debug, PartialEq)]
191/// # struct Pos(f32); impl Component for Pos { type Storage = VecStorage<Self>; }
192/// #
193/// # let mut world = World::new(); world.register::<Pos>();
194/// let entity = world.create_entity().with(Pos(0.1)).build();
195/// # let mut pos_storage = world.write_storage::<Pos>();
196///
197/// if let Ok(Some(p)) = pos_storage.insert(entity, Pos(4.0)) {
198/// println!("Overwrote {:?} with a new position", p);
199/// }
200/// ```
201///
202/// There's also an Entry-API similar to the one provided by
203/// `std::collections::HashMap`.
204pub type WriteStorage<'a, T> = Storage<'a, T, FetchMut<'a, MaskedStorage<T>>>;
205
206impl<'a, T> SystemData<'a> for WriteStorage<'a, T>
207where
208 T: Component,
209{
210 fn setup(res: &mut World) {
211 res.entry::<MaskedStorage<T>>()
212 .or_insert_with(|| MaskedStorage::new(<T::Storage as TryDefault>::unwrap_default()));
213 res.fetch_mut::<MetaTable<dyn AnyStorage>>()
214 .register::<MaskedStorage<T>>();
215 }
216
217 fn fetch(res: &'a World) -> Self {
218 Storage::new(res.fetch(), res.fetch_mut())
219 }
220
221 fn reads() -> Vec<ResourceId> {
222 vec![ResourceId::new::<EntitiesRes>()]
223 }
224
225 fn writes() -> Vec<ResourceId> {
226 vec![ResourceId::new::<MaskedStorage<T>>()]
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use crate::{prelude::*, storage::MaskedStorage};
233
234 struct Foo;
235 impl Component for Foo {
236 type Storage = VecStorage<Self>;
237 }
238
239 struct Sys;
240 impl<'a> System<'a> for Sys {
241 type SystemData = ReadStorage<'a, Foo>;
242
243 fn run(&mut self, _data: <Self as System>::SystemData) {
244 unimplemented!()
245 }
246 }
247
248 #[test]
249 fn uses_setup() {
250 let mut w = World::new();
251
252 let mut d = DispatcherBuilder::new().with(Sys, "sys", &[]).build();
253
254 assert!(!w.has_value::<MaskedStorage<Foo>>());
255
256 d.setup(&mut w);
257
258 assert!(w.has_value::<MaskedStorage<Foo>>());
259 }
260}