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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
// #![warn(clippy::all)]

/*!
 # Rinecs

 rinecs is a fast and easy to use ECS library oriented to work mostly in conjuntion
 with rin and associated crates

 ## ECS

 ECS stands for Entity Component System, understanding what this three elements
 mean and how they are used in rinecs will help you understand how to use rinecs

 ### Entity

 An entity in ECS is just an id, a number identifying such entity. In your application
 an entity could be a particle in a particle system or a character in a video game

 ### Component

 A component in ECS is the data that the application uses, each component is associated
 to an entity.

 For example in a particle system there could be components for the Position, Velocity,
 Size and Color.

 Each particle would have these components but there could be other entities with only
 some of this components or others in the same world

 ### System

 A system in ECS is the functionality that reads and modifies the components in the
 world

 For example in our particle system a ParticleUpdateSystem could add the Velocity to
 the Position of every entity that have both a Position and a Velocity

 Another system could for example change the Color based on the Velocity for entities
 that have both Color and Velocity

 ## Differences with object oriented programming

 In object oriented programming each object contains it's own data, for example
 in the particle system we are using as example if we used OO each particle would have
 it's own position, velocity, size, something like:

 ```
 struct Position{x: f32, y: f32}
 struct Velocity{x: f32, y: f32}

 struct Particle {
     position: Position,
     velocity: Velocity,
     size: f32,
 }
 ```

 Now if we wanted to update this particle each frame to change it's postion based on it's velocity
 we would usually create an update method that updated the position by adding the velocity to it.
 Let's say that we also want to update the size relative to the velocity of the particle:

 ```
 # struct Position{x: f32, y: f32}
 # struct Velocity{x: f32, y: f32}
 # struct Particle {
 #     position: Position,
 #     velocity: Velocity,
 #     size: f32,
 # }
 impl Particle{
     fn update(&mut self){
         self.position.x += self.velocity.x;
         self.position.x += self.velocity.y;
         self.size = self.velocity.x + self.velocity.y;
     }
 }
 ```

 Now we would create a vector of particles, update them all every frame and draw them afterwards
 probably through a draw method in the particle:

 ```
 # struct Position{x: f32, y: f32}
 # struct Velocity{x: f32, y: f32}
 # struct Particle {
 #     position: Position,
 #     velocity: Velocity,
 #     size: f32,
 # }
 # impl Particle{
 #     fn update(&mut self){}
 #     fn draw(&self){}
 # }
 let mut particles: Vec<Particle> = vec![];

 for particle in particles.iter_mut() {
     particle.update();
 }

 for particle in particles.iter() {
     particle.draw();
 }
 ```

 If we now wanted to add a new type of object that updated it's position in the same way that the
 particle does but didn't change it's size, lets say a FixedSizeParticle, we would need to reimplement
 all of the update and even the draw logic.

 In ECS the data for each particle is not contained on a specific object which solves this problem:

 ```
 #[macro_use] extern crate rinecs_derive;
 use rinecs::*;

 #[derive(Component, Debug, Clone, Copy)]
 pub struct Position{pub x: f32, pub y: f32}

 #[derive(Component, Debug, Clone, Copy)]
 pub struct Velocity{pub x: f32, pub y: f32}

 #[derive(Component, Debug, Clone, Copy)]
 pub struct Size(pub f32);

 #[system(name = "update position")]
 #[needs("Velocity")]
 #[updates("Position")]
 fn update_position_system(mut entities: Entities, resources: Resources){
     for (pos, vel) in entities.iter_for_mut::<(Write<Position>, Read<Velocity>)>(){
         pos.x += vel.x;
         pos.y += vel.y;
     }
 }

 #[system(name = "update size")]
 #[needs("Velocity")]
 #[updates("Size")]
 fn update_size_system(mut entities: Entities, resources: Resources){
     for (size, vel) in entities.iter_for_mut::<(Write<Size>, Read<Velocity>)>(){
         size.0 = vel.x + vel.y;
     }
 }

 #[system(name = "update velocity")]
 #[updates("Velocity")]
 fn update_velocity_system(mut entities: Entities, resources: Resources){
     for vel in entities.iter_for_mut::<Write<Velocity>>(){
         vel.x *= 0.9999;
         vel.y *= 0.9999;
     }
 }

 #[system_thread_local(name = "update size")]
 #[needs("Position", "Size")]
 fn renderer(entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
     for (pos, size) in entities.iter_for::<(Read<Position>, ReadOption<Size>)>(){
         let size = size.unwrap_or(&Size(10.));
         // draw circle at pos with radius size
     }
 }

 fn main(){
    let mut world = World::new();

    world.new_entity()
        .add(Position{x: 0., y: 0.})
        .add(Velocity{x: 10., y: 10.})
        .add(Size(0.));

    world.new_entity()
        .add(Position{x: 0., y: 0.})
        .add(Velocity{x: -10., y: -10.})
        .add(Size(0.));

    world.new_entity()
        .add(Position{x: 0., y: 0.})
        .add(Velocity{x: 10., y: -10.});

    world.add_system(update_velocity_system);
    world.add_system(update_position_system);
    world.add_system(update_size_system);
    world.add_system_thread_local(renderer);

    # let mut done = false;

    while !done {
        world.run_once();
    # done = true;
    }
 }
 ```

 Now the logic to update the position based on the velocity is independent from the
 particle, as well as all the other logic. We divide it in systems and each system
 knows what to do based on the data it uses. It doesn't know if the position belongs
 to a particle, a character or any other element in the system.

 Also now the updating of the postion and the size happen in parallel, in different threads,
 for free. Which can accelerate greatly the performance of the application if used properly.

 Apart from this, the memory layout in the ECS version is potentially much faster
 since all the positions, velocities and sizes are contiguous in memory. For something like
 the particle in our example it probably won't make any difference but for more complex
 obejcts with much more data the fact that each system only uses the data that it needs
 and that that data is contiguous in memory can make a big difference in terms of performance.

 Finally you might have noticed that the renderer in our example is added as a thread local
 system, this makes this system always run on the main thread which might be needed depending
 on the rendering technology you are using (for example with opengl).

 ## Operators

 In the previous example the different systems iterate over the data they use by using certain
 operators.

 For example the update_velocity system, only uses the `Write` operator with a `Velocity` parameter,
 this gives it access to all the velocity components in the world no matter to which entity they belong.

 In that example we've also used Read, which is similar to Write but gives read only access to the
 components and ReadOption that reads the component if that specific entity has it or returns None if
 not.

 Components can be grouped using tuples of types when specifying the operators.

 For the full documentation of all the operators in the system see [operators](operators)


 ## Filters

 In some cases it might be useful to treat a set of operators as an object. For example in the previous
 example we might be doing some operations in different systems. Instead of replicating the functionality
 we can use a Filter to group a set of components and implement methods over that object:

 ```
 # #[macro_use] extern crate rinecs_derive;
 # use rinecs::*;
 # #[derive(Component, Debug, Clone, Copy)]
 # pub struct Position{pub x: f32, pub y: f32}
 # #[derive(Component, Debug, Clone, Copy)]
 # pub struct Velocity{pub x: f32, pub y: f32}
 # #[derive(Component, Debug, Clone, Copy)]
 # pub struct Size(pub f32);
 #[derive(Filter)]
 struct Particle<'a>{
     position: Read<'a, Position>,
     size: ReadOption<'a, Size>,
 }

 impl<'a> Particle<'a>{
     fn render(&self){
         let size = self.size.unwrap_or(&Size(10.));
         println!("{},{} {}", self.position.x, self.position.y, size.0);
     }
 }

 fn renderer(entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
     for particle in entities.iter_for::<Particle>(){
         particle.render()
     }
 }
 ```

 As you can see in the previous example Filters can be used anywhere you would use an operator
 and equivalent to a tuple of all their members in terms of which entities they'll match

 ## Systems run order

 System's run order is determined by creating a dependencies graph from anotations in the system
 implementation.

 In the following example:

 ```
 #[macro_use] extern crate rinecs_derive;
 use rinecs::*;

 #[derive(Component, Debug, Clone, Copy)]
 pub struct Position{pub x: f32, pub y: f32}

 #[derive(Component, Debug, Clone, Copy)]
 pub struct Velocity{pub x: f32, pub y: f32}

 #[derive(Component, Debug, Clone, Copy)]
 pub struct Size(pub f32);

 #[system(name = "update position")]
 #[needs("Velocity")]
 #[updates("Position")]
 fn update_position_system(mut entities: Entities, resources: Resources){
     for (pos, vel) in entities.iter_for_mut::<(Write<Position>, Read<Velocity>)>(){
         pos.x += vel.x;
         pos.y += vel.y;
     }
 }

 #[system(name = "update size")]
 #[needs("Velocity")]
 #[updates("Size")]
 fn update_size_system(mut entities: Entities, resources: Resources){
     for (size, vel) in entities.iter_for_mut::<(Write<Size>, Read<Velocity>)>(){
         size.0 = vel.x + vel.y;
     }
 }

 #[system(name = "update velocity")]
 #[updates("Velocity")]
 fn update_velocity_system(mut entities: Entities, resources: Resources){
     for vel in entities.iter_for_mut::<Write<Velocity>>(){
         vel.x *= 0.9999;
         vel.y *= 0.9999;
     }
 }

 #[system_thread_local(name = "update size")]
 #[needs("Position", "Size")]
 fn renderer(entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
     for (pos, size) in entities.iter_for::<(Read<Position>, ReadOption<Size>)>(){
         let size = size.unwrap_or(&Size(10.));
         // draw circle at pos with radius size
     }
 }
 ```

 `update_position_system` specifies that it updates `Position` and needs `Velocity` and
 `update_velocity_system` updates velocity and doesn't need anything. That means that
 `update_velocity_system` will run before `update_position_system`.

 `update_size_system` needs `Velocity` and updates `Size` so it will run after
 `update_velocity_system` and in parallel with `update_position_system` since they don't have any
 dependency in common.

 Apart from `needs` and `updates` a system can also specify the following annotations:

 - `#[after("update_size_system")]` specifies that a system will run after `update_size_system`.
 - `#[before("update_size_system")]` specifies that a system will run before `update_size_system`.
 - `#[after_name("update size")] specifies that a system will run after the system with name
 "update size" as specified in it's `#[system(name="update size"]` anotation.
 - `#[before_name("update size")]` specifies that a system will run before the system with name
 "update size".
 - `#[read("Position")]` specifies that this system reads the Position component. This won't change
 the dependencies graph. It is only used to avoid running this systems in parallel with others that
 `updates` or `writes` to the `Position` components.
 - `#[writes("Position")]` specifies that this system writes the Position component. This won't change
 the dependencies graph. It is only used to avoid running this systems in parallel with others that
 `needs`, `reads`, `updates` or `writes` to the `Position` components.

 Although most times needs and updates are enough, sometimes a `needs` / `updates` graph can produce
 a cycle which is not allowed. In that case when running the world for the first time, the
 application will panic specifying the systems involved in that cycle. To solve it usually we can
 identify a system that doesn't need the very last information from the conflictive component and
 substitute a `needs` for a `reads`. Or perhaps identify a system which update is not really
 important for the dependency graph, and change an `updates` for a `writes`.

 The dependency graph can be debugged by printing it after adding all the systems using:

 ```
 # let mut world = rinecs::World::new();
 world.render_systems_dependency_graph("systems.dot");
 ```

 Which creates a vizgraph file with the systems dependency graph that can be viewed with any
 vizgraph application, or even plugins for several IDEs or text editors.
*/

#[cfg(feature="serde")]
#[macro_use] extern crate serde_derive;

#[allow(unused_imports)]
#[macro_use]
extern crate rinecs_derive;

#[doc(hidden)]
pub use rinecs_derive::*;


use sync::*;
// use storage::*;
#[doc(hidden)]
pub use storage::{
    Storage, IntoIter, IntoIterMut,
    HierarchicalStorage,
    HierarchicalOneToNStorage,
    OneToNStorage,
    StorageRef, IntoOrderedIter, IntoOrderedIterMut,
    CreationSto, StorageRegistry,
    StorageEntitiesExt,
    IntoSendStorage,
    IntoStorages,
};
#[doc(hidden)]
pub use operators::{
    Read,
    Write,
    Has,
    Not,
    HasOr,
    ReadNot,
    HasOption,
    ReadOption,
    WriteOption,
    ReadOr,
    Ref, ReadRef, URef,
    RefN,
    ReadAndParent,
    ReadAndParentRef,
    WriteAndParent,
    ReadHierarchical, WriteHierarchical,
    UnorderedData, UnorderedDataSend, OrderedData, OrderedDataSend,
    ChangedData, ChangedDataSend, ChangedOrderedData, ChangedOrderedDataSend, ChangesOrderedData,
    ChangesOrderedDataSend, ChangesData, ChangesDataSend,
    EntitiesData,
    FromComponent, TupleStorageEntities,
    Sto, DataAccesses,

};
#[cfg(feature = "parallel_iter")]
pub use operators::EntitiesDataParallel;

pub use entity::{
    Entity, Entities, EntitiesThreadLocal, EntitiesExt, EntityBuilder, EntitiesCreation,
    EntityStorages, EntityStoragesThreadLocal, EntityStoragesCreation, EntityStoragesExt
};
#[doc(hidden)]
pub use component::{Component, ComponentSend, ComponentThreadLocal,
    OneToNComponent, OneToNComponentSend, OneToNComponentThreadLocal,
    HierarchicalOneToNComponent, HierarchicalOneToNComponentSend, HierarchicalOneToNComponentThreadLocal,
    NToOneComponent, NToOneComponentSend, NToOneComponentThreadLocal,
    OneToOneComponent, OneToOneComponentSend, OneToOneComponentThreadLocal,
    Changes, ReferenceType

};
pub use resource::{
    Resources, ResourcesThreadLocal, ResourcesCreation, ResourcesExt, ResourcesThreadLocalExt,
    Res, ResMut
};
pub use world::World;
pub use systems::{
    System, SystemThreadLocal, CreationSystem, SystemCondition, SystemOnce, SystemOnceThreadLocal,
    SystemConditionSend, SystemConditionThreadLocal, SystemConditionCreation,
    Builder as SystemBuilder, BuilderThreadLocal as SystemBuilderThreadLocal,
    BuilderCreation as SystemBuilderCreation, SystemId, Barrier,
    BuilderConditionsThreadLocal, BuilderElseThreadLocal, BuilderConditions, BuilderElse,
    BuilderConditionsCreation, BuilderElseCreation, BuilderConditionsCreationOnce, BuilderElseCreationOnce,
};
#[cfg(feature="stats_events")]
pub use utils::Stat;
#[cfg(feature = "async")]
pub use systems::CreationSystemAsync;
#[doc(hidden)]
pub use idtree::{NodeRef, NodeRefMut, NodeId};
#[doc(hidden)]
pub use sync::{Ptr, PtrMut, NodePtr, NodePtrMut, ReadGuardRef, WriteGuardRef, CacheGuard};
pub use creation_context::{EntitiesCreationExt, ResourcesCreationExt, CreationContextExt};
#[doc(hidden)]
pub use bitmask::{Bitmask, MaskType};
#[cfg(feature = "debug_parameters")]
pub use debug::{SystemDebug, EntitiesDebug, DebugParameter};
#[cfg(all(unix, feature="dynamic_systems"))]
pub use libloading::os::unix::Symbol as DynamicSymbol;
#[cfg(all(windows, feature="dynamic_systems"))]
pub use libloading::os::windows::Symbol as DynamicSymbol;
#[cfg(feature="dynamic_systems")]
pub use dynamic_system_loader::DynamicFunction;
#[cfg(all(feature = "debug_locks", feature="parallel_systems", not(feature="lockfree")))]
use mutcell_dbg as mutcell;
pub use streaming_iterator::{self, StreamingIterator, StreamingIteratorMut};
pub use utils::{
    UniqueEntities, UniqueEntity, IntoEntitiesIterator, UniqueEntitiesIterWrapper,
    IntoUniqueIterator,
};
#[cfg(feature="parallel_iter")]
pub use utils::IntoUniqueParallelIterator;

#[cfg(not(feature = "debug_parameters"))]
pub trait DebugParameter: std::fmt::Debug{}

#[cfg(not(feature = "debug_parameters"))]
impl<D: std::fmt::Debug> DebugParameter for D{}

mod utils;
mod sync;
pub mod entity;
pub mod component;
pub mod storage;
mod idtree;
mod resource;
mod world;
mod systems;
mod bitmask;
mod creation_context;
pub mod operators;
#[cfg(all(feature="parallel_systems", feature="lockfree"))]
mod mutcell;

#[cfg(all(feature = "debug_locks", feature="parallel_systems", not(feature="lockfree")))]
mod mutcell_dbg;

#[cfg(feature = "debug_parameters")]
mod debug;

#[cfg(feature="dynamic_systems")]
mod dynamic_system_loader;

#[cfg(all(feature="lockfree", feature="debug_locks"))]
compile_error!("lockfree and debug_locks features can't be activated simultaneously");


#[cfg(all(not(feature="parallel_systems"), feature="debug_locks"))]
compile_error!("non parallel_systems and debug_locks features can't be activated simultaneously");