edict 1.0.0-rc9

Powerful entity-component-system library
Documentation
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
//! Queries are used to fetch data from the [`World`].
//!
//! Queries implement [`Query`] trait and are passed into methods by value.
//!
//! For convenience, `AsQuery` and `IntoQuery` traits are implemented for some types
//! to be used instead of queries in generic parameters.
//! For example [`Read<T>`] is a query to fetch `T` for reading, but `&T` implements [`AsQuery`]
//!
//! [`IntoQuery`] extends this to add conversion from type to a query carrying the state.
//! This trait is used extensively in the API to pass query by value.
//!
//! Stateless queries and some stateful queries with default state implement [`DefaultQuery`].
//! This trait is used extensively in the API to specify query type.
//!
//! Queries can be combined into tuples producing a new query that yields
//! a tuple of items from the original queries and filtering out entities
//! that don't satisfy all queries.
//!
//! Query can be used with [`World`] to produce a [`View`] parameterized with the query.
//! A [`View`] can be iterated to visit all matching entities and fetch
//! data from them.
//! [`View`] can also be indexed with [`Entity`] to fetch data from
//! a specific entity.
//! [`View`]s can also be used as function-system arguments.
//!
//! [`World`]: crate::world::World
//! [`View`]: crate::view::View
//! [`Entity`]: crate::entity::Entity
//!

use core::any::TypeId;

use crate::{
    Access, archetype::Archetype, component::ComponentInfo, entity::EntityId, epoch::EpochId,
};

pub use self::{
    alt::{Alt, FetchAlt, RefMut},
    // any_of::AnyOf,
    boolean::{
        And, And2, And3, And4, And5, And6, And7, And8, BooleanFetch, BooleanFetchOp, BooleanQuery,
        Or, Or2, Or3, Or4, Or5, Or6, Or7, Or8, Xor, Xor2, Xor3, Xor4, Xor5, Xor6, Xor7, Xor8,
    },
    borrow::{
        BorrowAll, BorrowAny, BorrowOne, FetchBorrowAllRead, FetchBorrowAnyRead,
        FetchBorrowAnyWrite, FetchBorrowOneRead, FetchBorrowOneWrite,
    },
    copied::{Cpy, FetchCpy},
    entities::{Entities, EntitiesFetch},
    fetch::{BatchFetch, Fetch, UnitFetch, VerifyFetch},
    filter::{FilteredFetch, Not, With, Without},
    modified::{
        Modified, ModifiedFetchAlt, ModifiedFetchCopied, ModifiedFetchRead, ModifiedFetchWith,
        ModifiedFetchWrite,
    },
    read::{FetchRead, Read},
    with_epoch::{EpochOf, FetchEpoch, WithEpoch},
    write::{FetchWrite, Write},
};

mod alt;
// mod any_of;
mod boolean;
mod borrow;
mod copied;
mod entities;
mod fetch;
mod filter;
mod modified;
mod option;
// mod phantom;
mod read;
mod tuple;
mod with_epoch;
mod write;

/// Types associated with a query type.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a query type",
    note = "If `{Self}` is a component type, use `&{Self}` or `&mut {Self}` instead"
)]
pub trait AsQuery {
    /// Associated query type.
    type Query: Query;
}

/// Detected write aliasing.
/// Should be either resolved at runtime or reported with panic.
pub struct WriteAlias;

/// Trait to query components from entities in the world.
/// Queries implement efficient iteration over entities while yielding
/// references to the components and optionally [`EntityId`] to address same components later.
///
/// [`EntityId`]: edict::entity::EntityId
///
/// # Safety
///
/// Implementations must adhere to unsafe contract of unsafe methods.
#[diagnostic::on_unimplemented(label = "`{Self}` is not a query type")]
pub unsafe trait Query: IntoQuery<Query = Self> + Copy + Send + Sync + 'static {
    /// Item type this query type yields.
    type Item<'a>: 'a;

    /// Fetch value type for this query type.
    /// Contains data from one archetype.
    type Fetch<'a>: Fetch<'a, Item = Self::Item<'a>> + 'a;

    /// Set to `true` if query may return mutable references to components.
    const MUTABLE: bool;

    /// Set to `true` if query filters individual entities.
    ///
    /// If set `false` - `Fetch` must unconditionally return `true` for all valid calls to
    /// `Fetch::visit_chunk` and `Fetch::visit_item`.
    const FILTERS_ENTITIES: bool = false;

    /// Returns what kind of access the query performs on the component type.
    /// This method may return stronger access type if it is impossible to know
    /// exact access with only type-id.
    fn component_access(&self, comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias>;

    /// Checks if archetype must be visited or skipped.
    /// If returns `false`, `access_archetype` and `fetch` must not be called,
    /// meaning that complex query should either skip archetype entirely or
    /// for this query specifically.
    ///
    /// If this method returns `true`, `access_archetype` and `fetch` must be safe to call.
    #[must_use]
    fn visit_archetype(&self, archetype: &Archetype) -> bool;

    /// Asks query to provide types and access for the specific archetype.
    /// Must call provided closure with type id and access pairs.
    /// Only types from archetype must be used to call closure.
    ///
    /// # Safety
    ///
    /// Must not be called if `visit_archetype` returned `false`.
    /// Implementation are allowed to assume conditions that make `visit_archetype` return `true`.
    unsafe fn access_archetype(&self, archetype: &Archetype, f: impl FnMut(TypeId, Access));

    /// Checks if archetype must be visited or skipped a second time after
    /// required access was granted.
    ///
    /// Most queries do not check visiting again so defaults to `true`.
    ///
    /// # Safety
    ///
    /// Must not be called if `visit_archetype` returned `false`.
    /// access_archetype must have been called before this method.
    #[must_use]
    #[inline]
    unsafe fn visit_archetype_late(&self, archetype: &Archetype) -> bool {
        debug_assert!(self.visit_archetype(archetype));
        let _ = archetype;
        true
    }

    /// Fetches data from one archetype.
    ///
    /// # Safety
    ///
    /// Must not be called if `visit_archetype` returned `false`.
    #[must_use]
    unsafe fn fetch<'a>(
        &self,
        arch_idx: u32,
        archetype: &'a Archetype,
        epoch: EpochId,
    ) -> Self::Fetch<'a>;

    /// Returns item for reserved entity if reserved entity (no components) satisfies the query.
    /// Otherwise returns `None`.
    #[must_use]
    #[inline]
    fn reserved_entity_item<'a>(&self, id: EntityId, idx: u32) -> Option<Self::Item<'a>> {
        let _ = id;
        let _ = idx;
        None
    }
}

/// Type alias for items returned by the [`Query`] type.
pub type QueryItem<'a, Q> = <<Q as AsQuery>::Query as Query>::Item<'a>;

/// Hack around inability to say `: Query<for<'a> Fetch<'a> = Self::BatchFetch<'a>>`
#[doc(hidden)]
pub trait BatchQueryHack<'a>: Query<Fetch<'a> = Self::BatchFetchHack> {
    /// Associated batch type.
    type BatchHack: 'a;

    /// Associated batch fetch type.
    type BatchFetchHack: BatchFetch<'a, Batch = Self::BatchHack> + 'a;
}

/// Extension trait for [`Query`] to provide additional methods to views.
pub trait BatchQuery: for<'a> BatchQueryHack<'a, BatchHack = Self::Batch<'a>> {
    /// Associated batch type.
    type Batch<'a>: 'a;
}

impl<'a, Q> BatchQueryHack<'a> for Q
where
    Q: Query,
    Q::Fetch<'a>: BatchFetch<'a>,
{
    type BatchHack = <Q::Fetch<'a> as BatchFetch<'a>>::Batch;
    type BatchFetchHack = Q::Fetch<'a>;
}

impl<Q> BatchQuery for Q
where
    Q: Query,
    for<'a> Q::Fetch<'a>: BatchFetch<'a>,
{
    type Batch<'a> = <Q::Fetch<'a> as BatchFetch<'a>>::Batch;
}

/// Type alias for items returned by the [`Query`] type.
pub type QueryBatch<'a, Q> = <<Q as AsQuery>::Query as BatchQuery>::Batch<'a>;

/// Types convertible into query type.
pub trait IntoQuery: AsQuery {
    /// Converts into query.
    fn into_query(self) -> Self::Query;
}

/// Default-constructible query type.
#[diagnostic::on_unimplemented(label = "`{Self}` is not a default-constructible query type")]
pub trait DefaultQuery: Query {
    /// Returns default query.
    fn default_query() -> Self;
}

impl<Q> DefaultQuery for Q
where
    Q: Query + Default,
{
    #[inline(always)]
    fn default_query() -> Self {
        Default::default()
    }
}

/// Types associated with default-constructible query type.
#[diagnostic::on_unimplemented(label = "`{Self}` is not a default-constructible query type")]
pub trait AsDefaultQuery: AsQuery<Query = Self::DefaultQuery> {
    /// Associated query type that is default-constructible.
    type DefaultQuery: DefaultQuery;

    /// Returns default query.
    #[inline(always)]
    fn default_query() -> Self::DefaultQuery {
        DefaultQuery::default_query()
    }
}

impl<Q> AsDefaultQuery for Q
where
    Q: AsQuery,
    Q::Query: DefaultQuery,
{
    type DefaultQuery = Q::Query;
}

/// Query that can be used from non-main thread.
///
/// # Safety
///
/// Query type must be safely usable from non-main thread.
/// This includes ensuring that any queried components
/// are `Sync` if queried immutably and `Send` if queried mutably.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a query type that can be used from non-main thread"
)]
pub unsafe trait SendQuery: Query {}

/// Query that can be used from non-main thread.
///
/// # Safety
///
/// Associated query type must implement [`SendQuery`].
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a query type that can be used from non-main thread"
)]
pub unsafe trait AsSendQuery: AsQuery<Query = Self::SendQuery> {
    /// Associated query type that can be used from non-main thread.
    type SendQuery: SendQuery;
}

unsafe impl<Q> AsSendQuery for Q
where
    Q: AsQuery,
    Q::Query: SendQuery,
{
    type SendQuery = Q::Query;
}

/// Types convertible into query type that can be used from non-main thread.
pub trait IntoSendQuery: IntoQuery + AsSendQuery {}
impl<Q> IntoSendQuery for Q where Q: IntoQuery + AsSendQuery {}

/// Query that does not mutate any components.
///
/// # Safety
///
/// [`Query`] must not borrow components mutably.
/// [`Query`] must not modify entities versions.
#[diagnostic::on_unimplemented(label = "`{Self}` mutates components")]
pub unsafe trait ImmutableQuery: Query {
    /// Checks that query is valid in compile time.
    const CHECK_VALID: () = {
        if Self::MUTABLE {
            panic!("Immutable query cannot fetch mutable components");
        }
    };
}

/// Type associated with a query type that does not mutate any components.
#[diagnostic::on_unimplemented(label = "`{Self}` mutates components")]
pub trait AsImmutableQuery: AsQuery<Query = Self::ImmutableQuery> {
    /// Associated query type that does not mutate any components.
    type ImmutableQuery: ImmutableQuery;
}

impl<Q> AsImmutableQuery for Q
where
    Q: AsQuery,
    Q::Query: ImmutableQuery,
{
    type ImmutableQuery = Q::Query;
}

/// Types convertible into query type that can be used from non-main thread.
pub trait IntoImmutableQuery: IntoQuery + AsImmutableQuery {}
impl<Q> IntoImmutableQuery for Q where Q: IntoQuery + AsImmutableQuery {}

/// Default-constructible query type that can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a default-constructible query type or cannot be used from non-main thread"
)]
pub trait DefaultSendQuery: DefaultQuery + SendQuery {}

impl<Q> DefaultSendQuery for Q where Q: DefaultQuery + SendQuery {}

/// Types associated with default-constructible query type that can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a default-constructible query type or cannot be used from non-main thread"
)]
pub trait AsDefaultSendQuery: AsQuery<Query = Self::DefaultSendQuery> {
    /// Associated query type that is default-constructible and can be used from non-main thread.
    type DefaultSendQuery: DefaultSendQuery;
}

impl<Q> AsDefaultSendQuery for Q
where
    Q: AsQuery,
    Q::Query: DefaultQuery + SendQuery,
{
    type DefaultSendQuery = Q::Query;
}

/// Default-constructible query type that can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a default-constructible query type or mutates components"
)]
pub trait DefaultImmutableQuery: DefaultQuery + ImmutableQuery {}

impl<Q> DefaultImmutableQuery for Q where Q: DefaultQuery + ImmutableQuery {}

/// Types associated with default-constructible query type that can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a default-constructible query type or mutates components"
)]
pub trait AsDefaultImmutableQuery: AsQuery<Query = Self::DefaultImmutableQuery> {
    /// Associated query type that is default-constructible and does not mutate any components.
    type DefaultImmutableQuery: DefaultImmutableQuery;
}

impl<Q> AsDefaultImmutableQuery for Q
where
    Q: AsQuery,
    Q::Query: DefaultQuery + ImmutableQuery,
{
    type DefaultImmutableQuery = Q::Query;
}

/// Query that does not mutate any components and can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` mutates components or cannot be used from non-main thread"
)]
pub trait SendImmutableQuery: SendQuery + ImmutableQuery {}
impl<Q> SendImmutableQuery for Q where Q: SendQuery + ImmutableQuery {}

/// Type associated with a query type that does not mutate any components and can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` mutates components or cannot be used from non-main thread"
)]
pub trait AsSendImmutableQuery: AsQuery<Query = Self::SendImmutableQuery> {
    /// Associated query type that does not mutate any components and can be used from non-main thread.
    type SendImmutableQuery: SendImmutableQuery;
}

impl<Q> AsSendImmutableQuery for Q
where
    Q: AsQuery,
    Q::Query: SendImmutableQuery,
{
    type SendImmutableQuery = Q::Query;
}

/// Types convertible into query type that can be used from non-main thread and does not mutate any components.
#[diagnostic::on_unimplemented(
    label = "`{Self}` mutates components or cannot be used from non-main thread"
)]
pub trait IntoSendImmutableQuery: IntoQuery + AsSendImmutableQuery {}
impl<Q> IntoSendImmutableQuery for Q where Q: IntoQuery + AsSendImmutableQuery {}

/// Default-constructible query type that can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a default-constructible query type or cannot be used from non-main thread"
)]
pub trait DefaultSendImmutableQuery: DefaultQuery + SendQuery + ImmutableQuery {}

impl<Q> DefaultSendImmutableQuery for Q where Q: DefaultQuery + SendQuery + ImmutableQuery {}

/// Types associated with default-constructible query type that can be used from non-main thread.
#[diagnostic::on_unimplemented(
    label = "`{Self}` is not a default-constructible query type or cannot be used from non-main thread"
)]
pub trait AsDefaultSendImmutableQuery: AsQuery<Query = Self::DefaultSendImmutableQuery> {
    /// Associated query type that is default-constructible and does not mutate any components and can be used from non-main thread.
    type DefaultSendImmutableQuery: DefaultSendImmutableQuery;
}

impl<Q> AsDefaultSendImmutableQuery for Q
where
    Q: AsQuery,
    Q::Query: DefaultQuery + SendQuery + ImmutableQuery,
{
    type DefaultSendImmutableQuery = Q::Query;
}