Skip to content

Commit

Permalink
docs: document query module
Browse files Browse the repository at this point in the history
  • Loading branch information
LechintanTudor committed Sep 1, 2024
1 parent 166b6f0 commit 4be4a41
Show file tree
Hide file tree
Showing 15 changed files with 132 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
comment_width = 100
comment_width = 80
force_multiline_blocks = true
imports_granularity = "Module"
max_width = 100
Expand Down
6 changes: 4 additions & 2 deletions src/component/group_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ pub const MIN_GROUP_ARITY: usize = 2;
/// Maximum number of component types that can form a group.
pub const MAX_GROUP_ARITY: usize = 16;

/// Maximum number of groups that can be set on a [`World`](crate::world::World).
/// Maximum number of groups that can be set on a
/// [`World`](crate::world::World).
pub const MAX_GROUP_COUNT: usize = 64;

/// Describes the layout of the component groups that can be set on a
Expand Down Expand Up @@ -166,7 +167,8 @@ impl GroupFamily {

/// Helper trait for creating groups in a [`GroupLayout`].
pub trait GroupDescriptor {
/// Slice containing the component data of the components present in the group.
/// Slice containing the component data of the components present in the
/// group.
const COMPONENTS: &'static [ComponentData];
}

Expand Down
9 changes: 6 additions & 3 deletions src/component/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use core::marker::PhantomData;
use core::ops::{Index, IndexMut};
use core::ptr::NonNull;

/// Shared view over all components of type `T` in a [`World`](crate::world::World).
/// Shared view over all components of type `T` in a
/// [`World`](crate::world::World).
pub struct View<'a, T> {
components: AtomicRef<'a, ComponentSparseSet>,
_phantom: PhantomData<&'a [T]>,
Expand All @@ -23,7 +24,8 @@ impl<'a, T> View<'a, T> {
}
}

/// Exclusive view over all components of type `T` in a [`World`](crate::world::World).
/// Exclusive view over all components of type `T` in a
/// [`World`](crate::world::World).
pub struct ViewMut<'a, T> {
components: AtomicRefMut<'a, ComponentSparseSet>,
_phantom: PhantomData<&'a mut [T]>,
Expand All @@ -42,7 +44,8 @@ where
}
}

/// Returns a mutable reference to the component mapped to `entity`, if it exists.
/// Returns a mutable reference to the component mapped to `entity`, if it
/// exists.
#[must_use]
pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
unsafe { self.components.get_mut::<T>(entity) }
Expand Down
9 changes: 6 additions & 3 deletions src/entity/sparse_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ impl SparseVec {
*self.entities.get(sparse)?
}

/// Returns the dense index at the given sparse index without checking if it valid.
/// Returns the dense index at the given sparse index without checking if it
/// valid.
#[inline]
#[must_use]
pub unsafe fn get_sparse_unchecked(&self, sparse: usize) -> usize {
Expand All @@ -83,7 +84,8 @@ impl SparseVec {
self.entities.get_mut(sparse)?.take()
}

/// Returns the entity slot at the given dense index without checking if it is valid.
/// Returns the entity slot at the given dense index without checking if it
/// is valid.
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut Option<DenseEntity> {
self.entities.get_unchecked_mut(index)
Expand All @@ -99,7 +101,8 @@ impl SparseVec {
unsafe { self.entities.get_unchecked_mut(index) }
}

/// Swaps the entities at the given dense indexes without checking their validity.
/// Swaps the entities at the given dense indexes without checking their
/// validity.
#[inline]
pub unsafe fn swap(&mut self, a: usize, b: usize) {
debug_assert!(a < self.entities.len());
Expand Down
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
//!
//! # Usage
//!
//! The most important items from Sparsey crate are [`World`] and [`Entity`], which are re-exported
//! at the root of the crate for easy access. A [`World`] is a collection of entities and components
//! thas supports create/read/update/delete (CRUD) operations, while an [`Entity`] is a versioned
//! index used to reference components within a [`World`].
//! The most important items from Sparsey crate are [`World`] and [`Entity`],
//! which are re-exported at the root of the crate for easy access. A [`World`]
//! is a collection of entities and components thas supports
//! create/read/update/delete (CRUD) operations, while an [`Entity`] is a
//! versioned index used to reference components within a [`World`].

#![cfg_attr(not(feature = "std"), no_std)]

Expand Down
5 changes: 5 additions & 0 deletions src/query/iter/dense_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::query::Query;
use core::ops::Range;
use core::ptr::NonNull;

/// Dense iterator over all items that match a query. Extremely fast.
#[must_use]
pub struct DenseIter<'a, G>
where
Expand Down Expand Up @@ -60,4 +61,8 @@ where

init
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
5 changes: 5 additions & 0 deletions src/query/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ pub use self::sparse_iter::*;

use crate::query::Query;

/// Sparse or dense iterator over all items that match the query.
#[must_use]
pub enum Iter<'a, G, I, E>
where
G: Query,
I: Query,
E: Query,
{
/// Sparse iterator.
Sparse(SparseIter<'a, G, I, E>),
/// Dense iterator. Extremely fast.
Dense(DenseIter<'a, G>),
}

Expand All @@ -23,11 +26,13 @@ where
I: Query,
E: Query,
{
/// Returns whether the iterator is sparse.
#[must_use]
pub const fn is_sparse(&self) -> bool {
matches!(self, Self::Sparse(_))
}

/// Returns whether the iterator is dense.
#[must_use]
pub const fn is_dense(&self) -> bool {
matches!(self, Self::Dense(_))
Expand Down
1 change: 1 addition & 0 deletions src/query/iter/sparse_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::entity::Entity;
use crate::query::Query;
use core::slice::Iter as SliceIter;

/// Sparse iterator over all items that match a query.
#[must_use]
pub struct SparseIter<'a, G, I, E>
where
Expand Down
44 changes: 37 additions & 7 deletions src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Query and iterate entities and components.

mod iter;
mod query_all;
mod query_one;
Expand All @@ -21,55 +23,83 @@ use core::mem::MaybeUninit;
use core::ops::Range;
use core::ptr;

pub trait Query {
/// Trait for querying and iterating one or more views.
///
/// # Safety
///
/// This trait is considered an implementation detail and cannot be safely
/// implemented outside the crate.
pub unsafe trait Query {
/// View borrowed from a [`World`].
type View<'a>;
type Item<'a>;

/// Item type returned by queries.
type Item<'a>: Send;

/// Type returned by [`slice`](Self::slice) operations.
type Slice<'a>;

/// [`SparseVec`](crate::entity::SparseVec) type used for sparse iteration.
type Sparse<'a>: Copy;

/// Data used for sparse and dense iteration.
type Data<'a>: Copy;

/// Borrows a view from the `world`.
#[must_use]
fn borrow(world: &World) -> Self::View<'_>;

/// Borrows a view from the `world` along with grouping information.
#[must_use]
fn borrow_with_group_info(world: &World) -> (Self::View<'_>, Option<QueryGroupInfo>);

/// Returns whether `entity` is present in all parts of the `view`.
#[must_use]
fn contains_all(view: &Self::View<'_>, entity: Entity) -> bool;

/// Returns whether `entity` is present in none of the parts of the `view`.
#[must_use]
fn contains_none(view: &Self::View<'_>, entity: Entity) -> bool;

/// Returns the item mapped to `entity`, if any.
#[must_use]
fn get<'a>(view: &'a mut Self::View<'_>, entity: Entity) -> Option<Self::Item<'a>>;

/// Splits the view into its entities and sparse vecs.
#[must_use]
fn split_sparse<'a>(view: &'a Self::View<'_>) -> (Option<&'a [Entity]>, Self::Sparse<'a>);

/// Returns whether `entity` is present in all sparse vecs.
#[must_use]
fn sparse_contains_all(sparse: Self::Sparse<'_>, entity: Entity) -> bool;

/// Returns whether `entity` is present in none of the sparse vecs.
#[must_use]
fn sparse_contains_none(sparse: Self::Sparse<'_>, entity: Entity) -> bool;

/// Splits the view into its entities, sparse vecs and data.
#[must_use]
fn split_sparse_data<'a>(
view: &'a Self::View<'_>,
) -> (Option<&'a [Entity]>, Self::Sparse<'a>, Self::Data<'a>);

/// Returns the item mapped to `entity`, if any.
#[must_use]
unsafe fn get_sparse<'a>(
sparse: Self::Sparse<'a>,
data: Self::Data<'a>,
entity: Entity,
) -> Option<Self::Item<'a>>;

/// Splits the view into its entities and data.
#[must_use]
fn split_dense_data<'a>(view: &'a Self::View<'_>) -> (Option<&'a [Entity]>, Self::Data<'a>);

/// Returns the item mapped to `index` or `entity`.
#[must_use]
unsafe fn get_dense(data: Self::Data<'_>, index: usize, entity: Entity) -> Self::Item<'_>;

/// Slices the data at the given `range`.
#[must_use]
unsafe fn slice<'a>(
data: Self::Data<'a>,
Expand All @@ -79,7 +109,7 @@ pub trait Query {
}

#[allow(clippy::unused_unit)]
impl Query for () {
unsafe impl Query for () {
type View<'a> = ();
type Item<'a> = ();
type Slice<'a> = ();
Expand Down Expand Up @@ -162,7 +192,7 @@ impl Query for () {
}
}

impl<Q> Query for Q
unsafe impl<Q> Query for Q
where
Q: QueryPart,
{
Expand Down Expand Up @@ -217,7 +247,7 @@ where
data: Self::Data<'a>,
entity: Entity,
) -> Option<Self::Item<'a>> {
let key = <Q as QueryPart>::get_sparse_key(sparse, entity)?;
let key = <Q as QueryPart>::get_dense_key(sparse, entity)?;
Some(<Q as QueryPart>::get_sparse(data, key))
}

Expand All @@ -240,7 +270,7 @@ where

macro_rules! impl_query {
($(($Ty:ident, $idx:tt)),+) => {
impl<$($Ty),+> Query for ($($Ty,)+)
unsafe impl<$($Ty),+> Query for ($($Ty,)+)
where
$($Ty: QueryPart,)+
{
Expand Down Expand Up @@ -356,7 +386,7 @@ macro_rules! impl_query {
data: Self::Data<'a>,
entity: Entity,
) -> Option<Self::Item<'a>> {
let key = ($($Ty::get_sparse_key(sparse.$idx, entity)?,)+);
let key = ($($Ty::get_dense_key(sparse.$idx, entity)?,)+);
Some(($($Ty::get_sparse(data.$idx, key.$idx),)+))
}

Expand Down
2 changes: 0 additions & 2 deletions src/query/par_iter/dense_par_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ where
impl<'a, G> ParallelIterator for DenseParIter<'a, G>
where
G: Query,
G::Item<'a>: Send,
{
type Item = G::Item<'a>;

Expand All @@ -80,7 +79,6 @@ where
impl<'a, G> IndexedParallelIterator for DenseParIter<'a, G>
where
G: Query,
G::Item<'a>: Send,
{
fn drive<C>(self, consumer: C) -> C::Result
where
Expand Down
1 change: 0 additions & 1 deletion src/query/par_iter/sparse_par_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ where
G: Query,
I: Query,
E: Query,
G::Item<'a>: Send,
{
type Item = G::Item<'a>;

Expand Down
8 changes: 7 additions & 1 deletion src/query/query_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use {
rayon::iter::ParallelIterator,
};

/// Queries all items that match a query.
#[must_use]
pub struct QueryAll<'a, G, I, E>
where
Expand Down Expand Up @@ -49,6 +50,7 @@ where
I: Query,
E: Query,
{
/// Returns an iterator over all items that match the query.
pub fn iter(&mut self) -> Iter<'_, G, I, E> {
if let Some(range) = self.get_group_range() {
let (get_entities, get_data) = G::split_dense_data(&self.get);
Expand Down Expand Up @@ -83,13 +85,15 @@ where
}
}

/// Calls `f` for all items that match the query.
pub fn for_each<F>(&mut self, f: F)
where
F: FnMut(G::Item<'_>),
{
self.iter().for_each(f);
}

/// Returns a parallel iterator over all items that match the query.
#[cfg(feature = "parallel")]
pub fn par_iter(&mut self) -> ParIter<'_, G, I, E> {
if let Some(range) = self.get_group_range() {
Expand Down Expand Up @@ -125,15 +129,17 @@ where
}
}

/// Calls `f` in parallel for all items that match the query.
#[cfg(feature = "parallel")]
pub fn par_for_each<F>(&mut self, f: F)
where
for<'b> G::Item<'b>: Send,
F: Fn(G::Item<'_>) + Send + Sync,
{
self.par_iter().for_each(f);
}

/// Returns ordered slices of all items that match the query, if the query
// is grouped.
#[must_use]
pub fn slice(&mut self) -> Option<G::Slice<'_>> {
let range = self.get_group_range()?;
Expand Down
Loading

0 comments on commit 4be4a41

Please sign in to comment.