use crate::{
change_detection::Tick,
storage::SparseSetIndex,
system::{SystemAccess, SystemMeta, SystemParam, SystemParamValidationError},
world::{unsafe_world_cell::UnsafeWorldCell, FromWorld, World},
};
use bevy_platform::sync::atomic::{AtomicUsize, Ordering};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct WorldId(usize);
static MAX_WORLD_ID: AtomicUsize = AtomicUsize::new(0);
impl WorldId {
pub fn new() -> Option<Self> {
#[cfg(feature = "std")]
{
MAX_WORLD_ID
.try_update(Ordering::Relaxed, Ordering::Relaxed, |val| {
val.checked_add(1)
})
.map(WorldId)
.ok()
}
#[cfg(not(feature = "std"))]
{
MAX_WORLD_ID
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |val| {
val.checked_add(1)
})
.map(WorldId)
.ok()
}
}
}
impl FromWorld for WorldId {
#[inline]
fn from_world(world: &mut World) -> Self {
world.id()
}
}
unsafe impl SystemParam for WorldId {
type State = ();
type Item<'world, 'state> = WorldId;
fn init_state(_: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
system_meta: &mut SystemMeta,
system_access: &mut SystemAccess,
_world: &mut World,
) {
system_access.require_shared_access::<Self>(system_meta);
}
#[inline]
unsafe fn get_param<'world, 'state>(
_: &'state mut Self::State,
_: &SystemMeta,
world: UnsafeWorldCell<'world>,
_: Tick,
) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
Ok(world.id())
}
}
impl SparseSetIndex for WorldId {
#[inline]
fn sparse_set_index(&self) -> usize {
self.0
}
#[inline]
fn get_sparse_set_index(value: usize) -> Self {
Self(value)
}
}
#[cfg(test)]
mod tests {
use crate::system::assert_is_system;
use super::*;
use alloc::vec::Vec;
#[test]
fn world_ids_unique() {
let ids = core::iter::repeat_with(WorldId::new)
.take(50)
.map(Option::unwrap)
.collect::<Vec<_>>();
for (i, &id1) in ids.iter().enumerate() {
for &id2 in ids.iter().skip(i + 1) {
assert_ne!(id1, id2, "WorldIds should not repeat");
}
}
}
#[test]
fn world_id_system_param() {
fn test_system(world_id: WorldId) -> WorldId {
world_id
}
let mut world = World::default();
let system_id = world.register_system(test_system);
let world_id = world.run_system(system_id).unwrap();
assert_eq!(world.id(), world_id);
}
#[test]
#[should_panic]
fn world_id_cannot_be_exclusive_system_param() {
fn test_system(_world: &mut World, world_id: WorldId) -> WorldId {
world_id
}
assert_is_system(test_system);
}
}