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