Path: blob/main/crates/bevy_ecs/src/world/identifier.rs
6604 views
use crate::{1component::Tick,2query::FilteredAccessSet,3storage::SparseSetIndex,4system::{ExclusiveSystemParam, ReadOnlySystemParam, SystemMeta, SystemParam},5world::{FromWorld, World},6};7use bevy_platform::sync::atomic::{AtomicUsize, Ordering};89use super::unsafe_world_cell::UnsafeWorldCell;1011#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]12// We use usize here because that is the largest `Atomic` we want to require13/// A unique identifier for a [`World`].14///15/// The trait [`FromWorld`] is implemented for this type, which returns the16/// ID of the world passed to [`FromWorld::from_world`].17// Note that this *is* used by external crates as well as for internal safety checks18pub struct WorldId(usize);1920/// The next [`WorldId`].21static MAX_WORLD_ID: AtomicUsize = AtomicUsize::new(0);2223impl WorldId {24/// Create a new, unique [`WorldId`]. Returns [`None`] if the supply of unique25/// [`WorldId`]s has been exhausted26///27/// Please note that the [`WorldId`]s created from this method are unique across28/// time - if a given [`WorldId`] is [`Drop`]ped its value still cannot be reused29pub fn new() -> Option<Self> {30MAX_WORLD_ID31// We use `Relaxed` here since this atomic only needs to be consistent with itself32.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |val| {33val.checked_add(1)34})35.map(WorldId)36.ok()37}38}3940impl FromWorld for WorldId {41#[inline]42fn from_world(world: &mut World) -> Self {43world.id()44}45}4647// SAFETY: No world data is accessed.48unsafe impl ReadOnlySystemParam for WorldId {}4950// SAFETY: No world data is accessed.51unsafe impl SystemParam for WorldId {52type State = ();5354type Item<'world, 'state> = WorldId;5556fn init_state(_: &mut World) -> Self::State {}5758fn init_access(59_state: &Self::State,60_system_meta: &mut SystemMeta,61_component_access_set: &mut FilteredAccessSet,62_world: &mut World,63) {64}6566#[inline]67unsafe fn get_param<'world, 'state>(68_: &'state mut Self::State,69_: &SystemMeta,70world: UnsafeWorldCell<'world>,71_: Tick,72) -> Self::Item<'world, 'state> {73world.id()74}75}7677impl ExclusiveSystemParam for WorldId {78type State = WorldId;79type Item<'s> = WorldId;8081fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {82world.id()83}8485fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {86*state87}88}8990impl SparseSetIndex for WorldId {91#[inline]92fn sparse_set_index(&self) -> usize {93self.094}9596#[inline]97fn get_sparse_set_index(value: usize) -> Self {98Self(value)99}100}101102#[cfg(test)]103mod tests {104use super::*;105use alloc::vec::Vec;106107#[test]108fn world_ids_unique() {109let ids = core::iter::repeat_with(WorldId::new)110.take(50)111.map(Option::unwrap)112.collect::<Vec<_>>();113for (i, &id1) in ids.iter().enumerate() {114// For the first element, i is 0 - so skip 1115for &id2 in ids.iter().skip(i + 1) {116assert_ne!(id1, id2, "WorldIds should not repeat");117}118}119}120121#[test]122fn world_id_system_param() {123fn test_system(world_id: WorldId) -> WorldId {124world_id125}126127let mut world = World::default();128let system_id = world.register_system(test_system);129let world_id = world.run_system(system_id).unwrap();130assert_eq!(world.id(), world_id);131}132133#[test]134fn world_id_exclusive_system_param() {135fn test_system(_world: &mut World, world_id: WorldId) -> WorldId {136world_id137}138139let mut world = World::default();140let system_id = world.register_system(test_system);141let world_id = world.run_system(system_id).unwrap();142assert_eq!(world.id(), world_id);143}144145// We cannot use this test as-is, as it causes other tests to panic due to using the same atomic variable.146// #[test]147// #[should_panic]148// fn panic_on_overflow() {149// MAX_WORLD_ID.store(usize::MAX - 50, Ordering::Relaxed);150// core::iter::repeat_with(WorldId::new)151// .take(500)152// .for_each(|_| ());153// }154}155156157