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
//! # stecs - static compiler-checked ECS*.
//!
//! For an introduction into the idea, see [this blogpost](https://nertsal.github.io/blog/so-i-wrote-my-own-ecs/).
//!
//! This library attempts to bridge the gap between
//! - compile-time guarantees, that are one of the important points of Rust;
//! - performance benefits of [SoA](https://en.wikipedia.org/wiki/AoS_and_SoA) (Struct of Array);
//! - and ease of use of ECS libraries
//!
//! **\*Note**: technically this library likely does not qualify as a proper ECS.
//! What this library actually is, is a generalized SoA derive
//! (For an example of a non-general one, see [soa_derive](https://crates.io/crates/soa_derive) or [soa-rs](https://crates.io/crates/soa-rs/)).
//!
//! This library contains and also generates snippets of unsafe code to support mutable querying.
//! It could be avoided by using lending iterators, but they are much less convenient to use in for-loops.
//! However, if possible, the goal is for the library to contain no unsafe code.
//!
//! # Example
//!
//! See the [GitHub repository](https://github.com/Nertsal/stecs/) for more examples.
//!
//! ```
//! # use stecs::prelude::*;
//! #[derive(SplitFields)]
//! struct Player {
//! position: f64,
//! health: Option<i64>,
//! }
//!
//! struct World {
//! players: StructOf<Vec<Player>>,
//! }
//!
//! let mut world = World { players: Default::default() };
//! world.players.insert(Player {
//! position: 1.0,
//! health: Some(5),
//! });
//!
//! for (pos, health) in query!(world.players, (&position, &mut health.Get.Some)) {
//! println!("player at {}; health: {}", pos, health);
//! *health -= 1;
//! }
//! ```
//!
//! # Archetypes
//!
//! Archetypes are entity types stored together for efficient access.
//! Here, the archetypes are static and defined by the user as regular structs with a derive macro.
//!
//! ```
//! # use stecs::prelude::*;
//! #
//! #[derive(SplitFields)]
//! struct Monster {
//! position: (f32, f32),
//! health: f32,
//! tick: usize,
//! damage: Option<f32>,
//! }
//! ```
//!
//! The main thing [`SplitFields`] macro generates is an analogous struct where each field is inside an abstract [`Storage`](storage::Storage) (for example, Vec).
//!
//! ```
//! # use stecs::prelude::*;
//! #
//! // Generated struct
//! struct MonsterStructOf<F: StorageFamily> {
//! position: F::Storage<(f32, f32)>,
//! health: F::Storage<f32>,
//! tick: F::Storage<usize>,
//! damage: F::Storage<Option<f32>>,
//! }
//! ```
//!
//! # Querying
//!
//! Archetypes form the basis of the library and can be used by themselves.
//! Though, accessing the required components manually may be inconvenient, so we offer more macros.
//!
//! Both [`query!`] and [`get!`] have almost identical syntax, and work by providing an archetype (or multiple, for a query), and then providing the target component view.
//!
//! The target view can be either a tuple or a struct (user-defined) with regular instantiation syntax, except for value expressions, which use optics.
//!
//! ```
//! # use stecs::prelude::*;
//! #
//! # struct World {
//! # units: StructOf<Vec<Unit>>,
//! # }
//! #
//! # #[derive(SplitFields)]
//! # struct Unit {
//! # position: f64,
//! # velocity: f64,
//! # }
//! #
//! # let mut world = World { units: Default::default() };
//! #
//! # struct TargetView<'a> {
//! # id: usize,
//! # position: &'a mut f64,
//! # velocity: &'a f64,
//! # }
//! #
//! # let id = world.units.insert(Unit { position: 0.0, velocity: 0.0 });
//! #
//! // Get position of a specific entity
//! let pos = get!(world.units, id, (&position)).unwrap();
//!
//! // Querying into a tuple
//! for (id, pos, vel) in query!(world.units, (id, &mut position, &velocity)) { }
//!
//! // Equivalent query into a struct
//! for view in query!(world.units, TargetView { id, position: &mut position, velocity }) { }
//! ```
//!
//! # Optics
//!
//! For an overview of optics in general, see [this tutorial](https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial) or [this Rust library](https://crates.io/crates/lens-rs).
//! This library provides only a very limited version of optics applicable to ECS component access.
//!
//! An optic has 3 distinguishable parts: **reference** type, **storage** access, and **component** access (optional).
//! The storage and component parts are separated by a `.Get` indicating access to a specific entity's component inside a storage, but can be omitted when not using the component part.
//!
//! **Note**: there's a special optic `id` (without `&`) that returns the id of the entity being queried.
//!
//! Take, for example, `&mut body.health.Get.Some`.
//!
//! 1. `&mut`. Each optic (except for `id`) must start by describing the **reference** type: either `&` or `&mut`.
//!
//! 2. `body.health`. The **storage** optic provides the path to the component storage.
//! It is usually a single identifier that is the name of the component.
//! But it can also be multiple dot-separated identifiers when querying inside a nested storage.
//!
//! 3. `.Some`. The **component** optic describes manipulations on the component value and starts after the `.Get`.
//! Typically, the component optic is either omitted or used to filter out optional components: `.Some`.
//!
//! In general, there are 3 things you can do in an optic:
//! - access a field, like in normal Rust: `position.x`
//! - get the component from the storage: `.Get`
//! - filter out optional components: `.Some`
//!
/// Derive macro for the static archetypes.
///
/// Generates:
/// - impl [`SplitFields`](crate::archetype::SplitFields)
/// - `XStructOf`, an analogous structure to the one being derived, with fields being general storages (see example below)
/// - `Ref` struct that is used when iterating over the generated archetype
/// - `RefMut` struct that is used when mutably iterating over the generated archetype
///
/// You can annotate the struct with `#[split(debug)]` to derive a [`Debug`](trait@std::fmt::Debug) impl
/// for the `Ref` and `RefMut` structs, and with `#[split(clone)]` to derive [`Clone`](trait@std::clone::Clone).
///
/// Also, you can annotate fields with `#[split(nested)]`, if that field is another archetype, to also split its fields.
///
/// # Example
///
/// ```
/// # use stecs::prelude::*;
/// #[derive(SplitFields)]
/// #[split(debug, clone)]
/// struct Position {
/// x: f64,
/// y: f64,
/// }
///
/// #[derive(SplitFields)]
/// #[split(debug, clone)]
/// struct Projectile {
/// #[split(nested)]
/// position: Position,
/// lifetime: f64,
/// }
/// ```
///
pub use SplitFields;
/// Get components of a specific entity.
///
/// Syntax is identical to [`query!`], with an additional `id` argument right after the archetype.
///
/// # Example
///
/// ```
/// # use stecs::prelude::*;
/// #
/// # struct World {
/// # units: StructOf<Vec<Unit>>,
/// # }
/// #
/// # #[derive(SplitFields)]
/// # struct Unit {
/// # position: f64,
/// # damage: Option<i64>,
/// # }
/// #
/// # let mut world = World { units: Default::default() };
/// #
/// # struct Target<'a> {
/// # position: &'a f64,
/// # damage: &'a i64,
/// # }
/// #
/// # let id = 0;
/// #
/// get!(world.units, id, (&position, &mut damage.Get.Some));
///
/// get!(
/// world.units,
/// id,
/// Target {
/// position,
/// damage: &mut damage.Get.Some
/// }
/// );
/// ```
///
pub use storage_get as get;
/// Query components from archetypes.
///
/// The general syntax for a query is: `query!(<archetype>, <view>)`.
///
/// # Example
///
/// ```
/// # use stecs::prelude::*;
/// #
/// # struct World {
/// # units: StructOf<Vec<Unit>>,
/// # }
/// #
/// # #[derive(SplitFields)]
/// # struct Unit {
/// # position: f64,
/// # damage: Option<i64>,
/// # }
/// #
/// # let mut world = World { units: Default::default() };
/// #
/// # struct Target<'a> {
/// # position: &'a f64,
/// # damage: &'a i64,
/// # }
/// #
/// for (pos, damage) in query!(world.units, (&position, &mut damage.Get.Some)) { }
///
/// for target in query!(
/// world.units,
/// Target {
/// position,
/// damage: &mut damage.Get.Some
/// }
/// ) { }
/// ```
///
/// ## Archetypes
/// A single archetype is provided as an expression that evaluates to an [`Archetype`](archetype::Archetype)
/// In typical cases, it is the field in the world with the type of `StructOf<_>`.
///
/// Multiple archetypes can be queried at the same time, if the target views match all archetypes,
/// by listing them in an array: `query!([world.projectiles, world.monsters], <view>)`.
///
/// ## View
/// Queried components can be viewed in either tuple or struct form.
/// In either case, the syntax is the same as normal struct/tuple construction,
/// except for value expressions which use the [optics](crate#optics).
///
pub use storage_query as query;
/// The traits for describing archetypes and split storages.
/// The [`Storage`](storage::Storage) trait and basic implementors.
/// use `stecs::prelude::*;` to import all necessary traits, types, and macros.