Skip to content

Commit

Permalink
Add tests and a module for WorldId
Browse files Browse the repository at this point in the history
  • Loading branch information
DJMcNab committed Sep 16, 2021
1 parent 29543de commit 35362b2
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 21 deletions.
54 changes: 54 additions & 0 deletions crates/bevy_ecs/src/world/identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::sync::atomic::{AtomicUsize, Ordering};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
// We use usize here because that is the largest `Atomic` we want to require
/// A unique identifier for a [`super::World`].
pub struct WorldId(usize);

/// The next [`WorldId`].
static MAX_WORLD_ID: AtomicUsize = AtomicUsize::new(0);

impl WorldId {
/// Create a new, unique [`WorldId`]
///
/// # Panics
/// If [`usize::MAX`] [`WorldId`]s have been created
// This could be kept crate private, but external crates may wish to create some for their tests
pub fn new() -> Self {
let id = MAX_WORLD_ID
// We use `Relaxed` here since this atomic only needs to be consistent with itself
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |val| {
val.checked_add(1)
})
.expect("More `bevy` `World`s have been created than is supported");
WorldId(id)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn world_ids_unique() {
let ids = std::iter::repeat_with(WorldId::new)
.take(50)
.collect::<Vec<_>>();
for (i, &id1) in ids.iter().enumerate() {
// For the first element, i is 0 - so skip 1
for &id2 in ids.iter().skip(i + 1) {
assert_ne!(id1, id2, "WorldIds should not repeat");
}
}
}

// We cannot use this test as-is, as it causes other tests to panic due to using the same atomic variable.
// #[test]
// #[should_panic]
// fn panic_on_overflow() {
// MAX_WORLD_ID.store(usize::MAX - 50, Ordering::Relaxed);
// std::iter::repeat_with(WorldId::new)
// .take(500)
// .for_each(|_| ());
// }
}
31 changes: 10 additions & 21 deletions crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,12 @@ use crate::{
use std::{
any::TypeId,
fmt,
sync::atomic::{AtomicU32, AtomicUsize, Ordering},
sync::atomic::{AtomicU32, Ordering},
};

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
// We use usize here because that is the largest `Atomic` we want to require
pub struct WorldId(usize);

/// The next [`WorldId`]. This will panic on overflow
static MAX_WORLD_ID: AtomicUsize = AtomicUsize::new(0);

impl Default for WorldId {
fn default() -> Self {
let id = MAX_WORLD_ID
// We use `Relaxed` here since this atomic only needs to be consistent with itself
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |val| {
val.checked_add(1)
})
.expect("More `bevy` `World`s have been created than is supported");
WorldId(id)
}
}
mod identifier;

pub use identifier::WorldId;
/// [World] stores and exposes operations on [entities](Entity), [components](Component),
/// and their associated metadata.
/// Each [Entity] has a set of components. Each component can have up to one instance of each
Expand All @@ -67,7 +51,7 @@ pub struct World {
impl Default for World {
fn default() -> Self {
Self {
id: Default::default(),
id: WorldId::new(),
entities: Default::default(),
components: Default::default(),
archetypes: Default::default(),
Expand All @@ -86,12 +70,17 @@ impl Default for World {

impl World {
/// Creates a new empty [World]
/// # Panics
///
/// If [`usize::MAX`] [`World`]s have been created.
/// This guarantee allows System Parameters to safely uniquely identify a [`World`],
/// since its [`WorldId`] is unique
#[inline]
pub fn new() -> World {
World::default()
}

/// Retrieves this world's unique ID
/// Retrieves this [`World`]'s unique ID
#[inline]
pub fn id(&self) -> WorldId {
self.id
Expand Down

0 comments on commit 35362b2

Please sign in to comment.