specs/lib.rs
1#![warn(missing_docs)]
2#![deny(unsafe_op_in_unsafe_fn)]
3#![deny(clippy::disallowed_types)]
4
5//! # SPECS Parallel ECS
6//!
7//! This library provides an ECS variant designed for parallel execution
8//! and convenient usage. It is highly flexible when it comes to actual
9//! component data and the way it is stored and accessed.
10//!
11//! Features:
12//!
13//! * depending on chosen features either 0 virtual function calls or one per
14//! system
15//! * parallel iteration over components
16//! * parallel execution of systems
17//!
18//! ## High-level overview
19//!
20//! One could basically split this library up into two parts:
21//! The data part and the execution part.
22//!
23//! ### The data
24//!
25//! `World` is where component storages, resources and entities are stored.
26//! See the docs of [`World`] for more.
27//!
28//! [`World`]: world/struct.World.html
29//!
30//! [`Component`]s can be easily implemented like this:
31//!
32//! [`Component`]: trait.Component.html
33//!
34//! ```rust
35//! use specs::prelude::*;
36//!
37//! struct MyComp;
38//!
39//! impl Component for MyComp {
40//! type Storage = VecStorage<Self>;
41//! }
42//! ```
43//!
44//! Or alternatively, if you enable the `"derive"` feature, you can use a
45//! custom `#[derive]` macro:
46//!
47//! ```rust
48//! # extern crate specs;
49//! # extern crate specs_derive;
50//! # #[cfg(not(feature = "specs-derive"))] use specs_derive::Component;
51//! # #[cfg(not(feature = "specs-derive"))] use specs::prelude::*;
52//!
53//! # #[cfg(feature = "specs-derive")]
54//! use specs::{prelude::*, Component};
55//!
56//! #[derive(Component)]
57//! #[storage(VecStorage)] // default is `DenseVecStorage`
58//! struct MyComp;
59//! # fn main() {}
60//! ```
61//!
62//! You can choose different storages according to your needs.
63//!
64//! These storages can be [`join`]ed together, for example joining a `Velocity`
65//! and a `Position` storage means you'll only get entities which have both of
66//! them. Thanks to rayon, this is even possible in parallel! See [`ParJoin`]
67//! for more.
68//!
69//! [`join`]: trait.Join.html#method.join
70//! [`ParJoin`]: trait.ParJoin.html
71//!
72//! ### System execution
73//!
74//! Here we have [`System`] and [`Dispatcher`] as our core types. Both types
75//! are provided by a library called `shred`.
76//!
77//! [`Dispatcher`]: struct.Dispatcher.html
78//! [`System`]: trait.System.html
79//!
80//! The `Dispatcher` can be seen as an optional part here;
81//! it allows dispatching the systems in parallel, given a list
82//! of systems and their dependencies on other systems.
83//!
84//! If you don't like it, you can also execute the systems yourself
85//! by using [`RunNow`].
86//!
87//! [`RunNow`]: trait.RunNow.html
88//!
89//! `System`s are traits with a `run()` method and an associated
90//! [`SystemData`], allowing type-safe aspects (knowledge about the
91//! reads / writes of the systems).
92//!
93//! [`SystemData`]: trait.SystemData.html
94//!
95//! ## Examples
96//!
97//! This is a basic example of using Specs:
98//!
99//! ```rust
100//! extern crate specs;
101//!
102//! use specs::prelude::*;
103//!
104//! // A component contains data which is
105//! // associated with an entity.
106//!
107//! struct Vel(f32);
108//!
109//! impl Component for Vel {
110//! type Storage = VecStorage<Self>;
111//! }
112//!
113//! struct Pos(f32);
114//!
115//! impl Component for Pos {
116//! type Storage = VecStorage<Self>;
117//! }
118//!
119//! struct SysA;
120//!
121//! impl<'a> System<'a> for SysA {
122//! // These are the resources required for execution.
123//! // You can also define a struct and `#[derive(SystemData)]`,
124//! // see the `full` example.
125//! type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>);
126//!
127//! fn run(&mut self, (mut pos, vel): Self::SystemData) {
128//! // The `.join()` combines multiple components,
129//! // so we only access those entities which have
130//! // both of them.
131//!
132//! // This joins the component storages for Position
133//! // and Velocity together; it's also possible to do this
134//! // in parallel using rayon's `ParallelIterator`s.
135//! // See `ParJoin` for more.
136//! for (pos, vel) in (&mut pos, &vel).join() {
137//! pos.0 += vel.0;
138//! }
139//! }
140//! }
141//!
142//! fn main() {
143//! // The `World` is our
144//! // container for components
145//! // and other resources.
146//!
147//! let mut world = World::new();
148//! world.register::<Pos>();
149//! world.register::<Vel>();
150//!
151//! // An entity may or may not contain some component.
152//!
153//! world.create_entity().with(Vel(2.0)).with(Pos(0.0)).build();
154//! world.create_entity().with(Vel(4.0)).with(Pos(1.6)).build();
155//! world.create_entity().with(Vel(1.5)).with(Pos(5.4)).build();
156//!
157//! // This entity does not have `Vel`, so it won't be dispatched.
158//! world.create_entity().with(Pos(2.0)).build();
159//!
160//! // This builds a dispatcher.
161//! // The third parameter of `add` specifies
162//! // logical dependencies on other systems.
163//! // Since we only have one, we don't depend on anything.
164//! // See the `full` example for dependencies.
165//! let mut dispatcher = DispatcherBuilder::new().with(SysA, "sys_a", &[]).build();
166//!
167//! // This dispatches all the systems in parallel (but blocking).
168//! dispatcher.dispatch(&mut world);
169//! }
170//! ```
171//!
172//! You can also easily create new entities on the fly:
173//!
174//! ```
175//! use specs::prelude::*;
176//!
177//! struct EnemySpawner;
178//!
179//! impl<'a> System<'a> for EnemySpawner {
180//! type SystemData = Entities<'a>;
181//!
182//! fn run(&mut self, entities: Entities<'a>) {
183//! let enemy = entities.create();
184//! }
185//! }
186//! ```
187//!
188//! See the repository's examples directory for more examples.
189
190pub extern crate hibitset;
191#[cfg(feature = "parallel")]
192pub extern crate rayon;
193pub extern crate shred;
194pub extern crate shrev;
195#[cfg(feature = "uuid_entity")]
196pub extern crate uuid;
197
198#[cfg(feature = "serde")]
199pub mod saveload;
200
201mod bitset;
202pub mod changeset;
203pub mod error;
204pub mod join;
205pub mod prelude;
206pub mod storage;
207pub mod world;
208
209pub use hibitset::BitSet;
210pub use shred::{
211 Accessor, AccessorCow, BatchAccessor, BatchController, BatchUncheckedWorld, Dispatcher,
212 DispatcherBuilder, Read, ReadExpect, RunNow, RunningTime, StaticAccessor, System, SystemData,
213 World, Write, WriteExpect,
214};
215pub use shrev::ReaderId;
216
217#[cfg(feature = "parallel")]
218pub use shred::AsyncDispatcher;
219
220#[cfg(feature = "specs-derive")]
221pub use specs_derive::{Component, ConvertSaveload};
222
223#[cfg(feature = "parallel")]
224pub use crate::join::ParJoin;
225pub use crate::{
226 changeset::ChangeSet,
227 join::{Join, LendJoin},
228 storage::{
229 DefaultVecStorage, DenseVecStorage, FlaggedStorage, HashMapStorage, NullStorage,
230 ReadStorage, Storage, Tracked, VecStorage, WriteStorage,
231 },
232 world::{Builder, Component, Entities, Entity, EntityBuilder, LazyUpdate, WorldExt},
233};
234
235pub use crate::storage::DerefFlaggedStorage;