Skip to content

Commit

Permalink
Merge pull request #64 from Anders429/registry_assert
Browse files Browse the repository at this point in the history
Assert Registry does not have duplicate components.
  • Loading branch information
Anders429 authored Mar 14, 2022
2 parents cf15908 + 46ad69b commit 80f7eca
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
73 changes: 73 additions & 0 deletions src/registry/seal/assertions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! This module defines and implements assertions on a [`Registry`].
//!
//! All assertions on invariants that must be upheld by a `Registry` should be included within the
//! `Assertions` trait defined here. This trait acts as an extension to the [`registry::Seal`]
//! trait, implementing it on all registries.
//!
//! [`Registry`]: crate::registry::Registry
//! [`registry::Seal`]: crate::registry::seal::Seal;

use crate::{component::Component, registry::Null};
use core::any::TypeId;
use hashbrown::HashSet;

/// Assertions that can be run on a registry to verify that certain invariants are upheld.
pub trait Assertions {
/// Asserts that no components within the registry are of the same type.
///
/// This is necessary to ensure that logic within a [`World`] is sound, as some logic relies on
/// the assumption that there is only one component within the registry. Therefore, this
/// assertion should be made when initializing a new `World` with a registry so that the
/// registry code internally is sound.
///
/// [`World`]: crate::world::World
fn assert_no_duplicates(components: &mut HashSet<TypeId>);
}

impl Assertions for Null {
fn assert_no_duplicates(_components: &mut HashSet<TypeId>) {}
}

impl<C, R> Assertions for (C, R)
where
C: Component,
R: Assertions,
{
fn assert_no_duplicates(components: &mut HashSet<TypeId>) {
assert!(components.insert(TypeId::of::<C>()));
R::assert_no_duplicates(components);
}
}

#[cfg(test)]
mod tests {
use super::Assertions;
use crate::registry;
use hashbrown::HashSet;

struct A;
struct B;
struct C;

#[test]
fn no_duplicates() {
type NoDuplicates = registry!(A, B, C);

NoDuplicates::assert_no_duplicates(&mut HashSet::new());
}

#[test]
fn empty_no_duplicates() {
type Empty = registry!();

Empty::assert_no_duplicates(&mut HashSet::new());
}

#[test]
#[should_panic]
fn has_duplicates() {
type HasDuplicates = registry!(A, B, A, C);

HasDuplicates::assert_no_duplicates(&mut HashSet::new());
}
}
4 changes: 3 additions & 1 deletion src/registry/seal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod assertions;
mod length;
mod storage;

use crate::{component::Component, registry::Null};
use assertions::Assertions;
use length::Length;
use storage::Storage;

pub trait Seal: Length + Storage {}
pub trait Seal: Assertions + Length + Storage {}

impl Seal for Null {}

Expand Down
4 changes: 3 additions & 1 deletion src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{
};
use alloc::{vec, vec::Vec};
use core::any::TypeId;
use hashbrown::HashMap;
use hashbrown::{HashMap, HashSet};

/// A container of entities.
///
Expand Down Expand Up @@ -89,6 +89,8 @@ where
entity_allocator: entity::Allocator<R>,
len: usize,
) -> Self {
R::assert_no_duplicates(&mut HashSet::with_capacity(R::LEN));

let mut component_map = HashMap::new();
R::create_component_map(&mut component_map, 0);

Expand Down

0 comments on commit 80f7eca

Please sign in to comment.