mod entity_ref;
mod spawn_batch;
mod world_cell;

pub use crate::change_detection::Mut;
pub use entity_ref::*;
pub use spawn_batch::*;
pub use world_cell::*;

use crate::{
    archetype::{ArchetypeComponentId, ArchetypeComponentInfo, ArchetypeId, Archetypes},
    bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
    change_detection::Ticks,
    component::{Component, ComponentId, ComponentTicks, Components, StorageType},
    entity::{AllocAtWithoutReplacement, Entities, Entity},
    query::{FilterFetch, QueryState, WorldQuery},
    storage::{Column, SparseSet, Storages},
    system::Resource,
};
use std::{
    any::TypeId,
    fmt,
    sync::atomic::{AtomicU32, Ordering},
};

mod identifier;

pub use identifier::WorldId;
/// Stores and exposes operations on [entities](Entity), [components](Component), resources,
/// and their associated metadata.
///
/// Each [Entity] has a set of components. Each component can have up to one instance of each
/// component type. Entity components can be created, updated, removed, and queried using a given
/// [World].
///
/// # Resources
///
/// Worlds can also store *resources*, which are unique instances of a given type that don't
/// belong to a specific Entity. There are also *non send resources*, which can only be
/// accessed on the main thread.
///
/// ## Usage of global resources
///
/// 1. Insert the resource into the `World`, using [`World::insert_resource`].
/// 2. Fetch the resource from a system, using [`Res`](crate::system::Res) or [`ResMut`](crate::system::ResMut).
///
/// ```
/// # let mut world = World::default();
/// # let mut schedule = Schedule::default();
/// # schedule.add_stage("update", SystemStage::parallel());
/// # use bevy_ecs::prelude::*;
/// #
/// struct MyResource { value: u32 }
///
/// world.insert_resource(MyResource { value: 42 });
///
/// fn read_resource_system(resource: Res<MyResource>) {
///     assert_eq!(resource.value, 42);
/// }
///
/// fn write_resource_system(mut resource: ResMut<MyResource>) {
///     assert_eq!(resource.value, 42);
///     resource.value = 0;
///     assert_eq!(resource.value, 0);
/// }
/// #
/// # schedule.add_system_to_stage("update", read_resource_system.label("first"));
/// # schedule.add_system_to_stage("update", write_resource_system.after("first"));
/// # schedule.run_once(&mut world);
/// ```
pub struct World {
    id: WorldId,
    pub(crate) entities: Entities,
    pub(crate) components: Components,
    pub(crate) archetypes: Archetypes,
    pub(crate) storages: Storages,
    pub(crate) bundles: Bundles,
    pub(crate) removed_components: SparseSet<ComponentId, Vec<Entity>>,
    /// Access cache used by [WorldCell].
    pub(crate) archetype_component_access: ArchetypeComponentAccess,
    main_thread_validator: MainThreadValidator,
    pub(crate) change_tick: AtomicU32,
    pub(crate) last_change_tick: u32,
}

impl Default for World {
    fn default() -> Self {
        Self {
            id: WorldId::new().expect("More `bevy` `World`s have been created than is supported"),
            entities: Default::default(),
            components: Default::default(),
            archetypes: Default::default(),
            storages: Default::default(),
            bundles: Default::default(),
            removed_components: Default::default(),
            archetype_component_access: Default::default(),
            main_thread_validator: Default::default(),
            // Default value is `1`, and `last_change_tick`s default to `0`, such that changes
            // are detected on first system runs and for direct world queries.
            change_tick: AtomicU32::new(1),
            last_change_tick: 0,
        }
    }
}

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
    #[inline]
    pub fn id(&self) -> WorldId {
        self.id
    }

    /// Retrieves this world's [Entities] collection
    #[inline]
    pub fn entities(&self) -> &Entities {
        &self.entities
    }

    /// Retrieves this world's [Entities] collection mutably
    #[inline]
    pub fn entities_mut(&mut self) -> &mut Entities {
        &mut self.entities
    }

    /// Retrieves this world's [Archetypes] collection
    #[inline]
    pub fn archetypes(&self) -> &Archetypes {
        &self.archetypes
    }

    /// Retrieves this world's [Components] collection
    #[inline]
    pub fn components(&self) -> &Components {
        &self.components
    }

    /// Retrieves a mutable reference to this world's [Components] collection
    #[inline]
    pub fn components_mut(&mut self) -> &mut Components {
        &mut self.components
    }

    /// Retrieves this world's [Storages] collection
    #[inline]
    pub fn storages(&self) -> &Storages {
        &self.storages
    }

    /// Retrieves this world's [Bundles] collection
    #[inline]
    pub fn bundles(&self) -> &Bundles {
        &self.bundles
    }

    /// Retrieves a [`WorldCell`], which safely enables multiple mutable World accesses at the same
    /// time, provided those accesses do not conflict with each other.
    #[inline]
    pub fn cell(&mut self) -> WorldCell<'_> {
        WorldCell::new(self)
    }

    pub fn init_component<T: Component>(&mut self) -> ComponentId {
        self.components.init_component::<T>(&mut self.storages)
    }

    /// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`.
    /// This will panic if the `entity` does not exist. Use [`World::get_entity`] if you want
    /// to check for entity existence instead of implicitly panic-ing.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    ///
    /// let position = world.entity(entity).get::<Position>().unwrap();
    /// assert_eq!(position.x, 0.0);
    /// ```
    #[inline]
    pub fn entity(&self, entity: Entity) -> EntityRef {
        // Lazily evaluate panic!() via unwrap_or_else() to avoid allocation unless failure
        self.get_entity(entity)
            .unwrap_or_else(|| panic!("Entity {:?} does not exist", entity))
    }

    /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`.
    /// This will panic if the `entity` does not exist. Use [`World::get_entity_mut`] if you want
    /// to check for entity existence instead of implicitly panic-ing.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    ///
    /// let mut position = world.entity_mut(entity).get_mut::<Position>().unwrap();
    /// position.x = 1.0;
    /// ```
    #[inline]
    pub fn entity_mut(&mut self, entity: Entity) -> EntityMut {
        // Lazily evaluate panic!() via unwrap_or_else() to avoid allocation unless failure
        self.get_entity_mut(entity)
            .unwrap_or_else(|| panic!("Entity {:?} does not exist", entity))
    }

    /// Returns an [`EntityMut`] for the given `entity` (if it exists) or spawns one if it doesn't exist.
    /// This will return [`None`] if the `entity` exists with a different generation.
    ///
    /// # Note
    /// Spawning a specific `entity` value is rarely the right choice. Most apps should favor [`World::spawn`].
    /// This method should generally only be used for sharing entities across apps, and only when they have a
    /// scheme worked out to share an ID space (which doesn't happen by default).
    #[inline]
    pub fn get_or_spawn(&mut self, entity: Entity) -> Option<EntityMut> {
        self.flush();
        match self.entities.alloc_at_without_replacement(entity) {
            AllocAtWithoutReplacement::Exists(location) => {
                // SAFE: `entity` exists and `location` is that entity's location
                Some(unsafe { EntityMut::new(self, entity, location) })
            }
            AllocAtWithoutReplacement::DidNotExist => {
                // SAFE: entity was just allocated
                Some(unsafe { self.spawn_at_internal(entity) })
            }
            AllocAtWithoutReplacement::ExistsWithWrongGeneration => None,
        }
    }

    /// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`.
    /// Returns [`None`] if the `entity` does not exist. Use [`World::entity`] if you don't want
    /// to unwrap the [`EntityRef`] yourself.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    ///
    /// let entity_ref = world.get_entity(entity).unwrap();
    /// let position = entity_ref.get::<Position>().unwrap();
    /// assert_eq!(position.x, 0.0);
    /// ```
    #[inline]
    pub fn get_entity(&self, entity: Entity) -> Option<EntityRef> {
        let location = self.entities.get(entity)?;
        Some(EntityRef::new(self, entity, location))
    }

    /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`.
    /// Returns [`None`] if the `entity` does not exist. Use [`World::entity_mut`] if you don't want
    /// to unwrap the [`EntityMut`] yourself.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    ///
    /// let mut entity_mut = world.get_entity_mut(entity).unwrap();
    /// let mut position = entity_mut.get_mut::<Position>().unwrap();
    /// position.x = 1.0;
    /// ```
    #[inline]
    pub fn get_entity_mut(&mut self, entity: Entity) -> Option<EntityMut> {
        let location = self.entities.get(entity)?;
        // SAFE: `entity` exists and `location` is that entity's location
        Some(unsafe { EntityMut::new(self, entity, location) })
    }

    /// Spawns a new [`Entity`] and returns a corresponding [`EntityMut`], which can be used
    /// to add components to the entity or retrieve its id.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    /// #[derive(Component)]
    /// struct Label(&'static str);
    /// #[derive(Component)]
    /// struct Num(u32);
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 }) // add a single component
    ///     .insert_bundle((Num(1), Label("hello"))) // add a bundle of components
    ///     .id();
    ///
    /// let position = world.entity(entity).get::<Position>().unwrap();
    /// assert_eq!(position.x, 0.0);
    /// ```
    pub fn spawn(&mut self) -> EntityMut {
        self.flush();
        let entity = self.entities.alloc();
        // SAFE: entity was just allocated
        unsafe { self.spawn_at_internal(entity) }
    }

    /// # Safety
    /// must be called on an entity that was just allocated
    unsafe fn spawn_at_internal(&mut self, entity: Entity) -> EntityMut {
        let archetype = self.archetypes.empty_mut();
        // PERF: consider avoiding allocating entities in the empty archetype unless needed
        let table_row = self.storages.tables[archetype.table_id()].allocate(entity);
        // SAFE: no components are allocated by archetype.allocate() because the archetype is
        // empty
        let location = archetype.allocate(entity, table_row);
        // SAFE: entity index was just allocated
        self.entities
            .meta
            .get_unchecked_mut(entity.id() as usize)
            .location = location;
        EntityMut::new(self, entity, location)
    }

    /// Spawns a batch of entities with the same component [Bundle] type. Takes a given [Bundle]
    /// iterator and returns a corresponding [Entity] iterator.
    /// This is more efficient than spawning entities and adding components to them individually,
    /// but it is limited to spawning entities with the same [Bundle] type, whereas spawning
    /// individually is more flexible.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, entity::Entity, world::World};
    ///
    /// #[derive(Component)]
    /// struct Str(&'static str);
    /// #[derive(Component)]
    /// struct Num(u32);
    ///
    /// let mut world = World::new();
    /// let entities = world.spawn_batch(vec![
    ///   (Str("a"), Num(0)), // the first entity
    ///   (Str("b"), Num(1)), // the second entity
    /// ]).collect::<Vec<Entity>>();
    ///
    /// assert_eq!(entities.len(), 2);
    /// ```
    pub fn spawn_batch<I>(&mut self, iter: I) -> SpawnBatchIter<'_, I::IntoIter>
    where
        I: IntoIterator,
        I::Item: Bundle,
    {
        SpawnBatchIter::new(self, iter.into_iter())
    }

    /// Retrieves a reference to the given `entity`'s [Component] of the given type.
    /// Returns [None] if the `entity` does not have a [Component] of the given type.
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    /// let position = world.get::<Position>(entity).unwrap();
    /// assert_eq!(position.x, 0.0);
    /// ```
    #[inline]
    pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
        self.get_entity(entity)?.get()
    }

    /// Retrieves a mutable reference to the given `entity`'s [Component] of the given type.
    /// Returns [None] if the `entity` does not have a [Component] of the given type.
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    /// let mut position = world.get_mut::<Position>(entity).unwrap();
    /// position.x = 1.0;
    /// ```
    #[inline]
    pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<Mut<T>> {
        self.get_entity_mut(entity)?.get_mut()
    }

    /// Despawns the given `entity`, if it exists. This will also remove all of the entity's
    /// [Component]s. Returns `true` if the `entity` is successfully despawned and `false` if
    /// the `entity` does not exist.
    /// ```
    /// use bevy_ecs::{component::Component, world::World};
    ///
    /// #[derive(Component)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entity = world.spawn()
    ///     .insert(Position { x: 0.0, y: 0.0 })
    ///     .id();
    /// assert!(world.despawn(entity));
    /// assert!(world.get_entity(entity).is_none());
    /// assert!(world.get::<Position>(entity).is_none());
    /// ```
    #[inline]
    pub fn despawn(&mut self, entity: Entity) -> bool {
        self.get_entity_mut(entity)
            .map(|e| {
                e.despawn();
                true
            })
            .unwrap_or(false)
    }

    /// Clears component tracker state
    pub fn clear_trackers(&mut self) {
        for entities in self.removed_components.values_mut() {
            entities.clear();
        }

        self.last_change_tick = self.increment_change_tick();
    }

    /// Returns [`QueryState`] for the given [`WorldQuery`], which is used to efficiently
    /// run queries on the [`World`] by storing and reusing the [`QueryState`].
    /// ```
    /// use bevy_ecs::{component::Component, entity::Entity, world::World};
    ///
    /// #[derive(Component, Debug, PartialEq)]
    /// struct Position {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// #[derive(Component)]
    /// struct Velocity {
    ///   x: f32,
    ///   y: f32,
    /// }
    ///
    /// let mut world = World::new();
    /// let entities = world.spawn_batch(vec![
    ///     (Position { x: 0.0, y: 0.0}, Velocity { x: 1.0, y: 0.0 }),
    ///     (Position { x: 0.0, y: 0.0}, Velocity { x: 0.0, y: 1.0 }),
    /// ]).collect::<Vec<Entity>>();
    ///
    /// let mut query = world.query::<(&mut Position, &Velocity)>();
    /// for (mut position, velocity) in query.iter_mut(&mut world) {
    ///    position.x += velocity.x;
    ///    position.y += velocity.y;
    /// }
    ///
    /// assert_eq!(world.get::<Position>(entities[0]).unwrap(), &Position { x: 1.0, y: 0.0 });
    /// assert_eq!(world.get::<Position>(entities[1]).unwrap(), &Position { x: 0.0, y: 1.0 });
    /// ```
    ///
    /// To iterate over entities in a deterministic order,
    /// sort the results of the query using the desired component as a key.
    /// Note that this requires fetching the whole result set from the query
    /// and allocation of a [Vec] to store it.
    ///
    /// ```
    /// use bevy_ecs::{component::Component, entity::Entity, world::World};
    ///
    /// #[derive(Component, PartialEq, Eq, PartialOrd, Ord, Debug)]
    /// struct Order(i32);
    /// #[derive(Component, PartialEq, Debug)]
    /// struct Label(&'static str);
    ///
    /// let mut world = World::new();
    /// let a = world.spawn().insert_bundle((Order(2), Label("second"))).id();
    /// let b = world.spawn().insert_bundle((Order(3), Label("third"))).id();
    /// let c = world.spawn().insert_bundle((Order(1), Label("first"))).id();
    /// let mut entities = world.query::<(Entity, &Order, &Label)>()
    ///     .iter(&world)
    ///     .collect::<Vec<_>>();
    /// // Sort the query results by their `Order` component before comparing
    /// // to expected results. Query iteration order should not be relied on.
    /// entities.sort_by_key(|e| e.1);
    /// assert_eq!(entities, vec![
    ///     (c, &Order(1), &Label("first")),
    ///     (a, &Order(2), &Label("second")),
    ///     (b, &Order(3), &Label("third")),
    /// ]);
    /// ```
    #[inline]
    pub fn query<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
        QueryState::new(self)
    }

    /// Returns [`QueryState`] for the given filtered [`WorldQuery`], which is used to efficiently
    /// run queries on the [`World`] by storing and reusing the [`QueryState`].
    /// ```
    /// use bevy_ecs::{component::Component, entity::Entity, world::World, query::With};
    ///
    /// #[derive(Component)]
    /// struct A;
    /// #[derive(Component)]
    /// struct B;
    ///
    /// let mut world = World::new();
    /// let e1 = world.spawn().insert(A).id();
    /// let e2 = world.spawn().insert_bundle((A, B)).id();
    ///
    /// let mut query = world.query_filtered::<Entity, With<B>>();
    /// let matching_entities = query.iter(&world).collect::<Vec<Entity>>();
    ///
    /// assert_eq!(matching_entities, vec![e2]);
    /// ```
    #[inline]
    pub fn query_filtered<Q: WorldQuery, F: WorldQuery>(&mut self) -> QueryState<Q, F>
    where
        F::Fetch: FilterFetch,
    {
        QueryState::new(self)
    }

    /// Returns an iterator of entities that had components of type `T` removed
    /// since the last call to [`World::clear_trackers`].
    pub fn removed<T: Component>(&self) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> {
        if let Some(component_id) = self.components.get_id(TypeId::of::<T>()) {
            self.removed_with_id(component_id)
        } else {
            [].iter().cloned()
        }
    }

    /// Returns an iterator of entities that had components with the given `component_id` removed
    /// since the last call to [`World::clear_trackers`].
    pub fn removed_with_id(
        &self,
        component_id: ComponentId,
    ) -> std::iter::Cloned<std::slice::Iter<'_, Entity>> {
        if let Some(removed) = self.removed_components.get(component_id) {
            removed.iter().cloned()
        } else {
            [].iter().cloned()
        }
    }

    /// Inserts a new resource with the given `value`.
    /// Resources are "unique" data of a given type.
    #[inline]
    pub fn insert_resource<T: Resource>(&mut self, value: T) {
        let component_id = self.components.init_resource::<T>();
        // SAFE: component_id just initialized and corresponds to resource of type T
        unsafe { self.insert_resource_with_id(component_id, value) };
    }

    /// Inserts a new non-send resource with the given `value`.
    /// Resources are "unique" data of a given type.
    #[inline]
    pub fn insert_non_send<T: 'static>(&mut self, value: T) {
        self.validate_non_send_access::<T>();
        let component_id = self.components.init_non_send::<T>();
        // SAFE: component_id just initialized and corresponds to resource of type T
        unsafe { self.insert_resource_with_id(component_id, value) };
    }

    /// Removes the resource of a given type and returns it, if it exists. Otherwise returns [None].
    /// Resources are "unique" data of a given type.
    #[inline]
    pub fn remove_resource<T: Resource>(&mut self) -> Option<T> {
        // SAFE: T is Send + Sync
        unsafe { self.remove_resource_unchecked() }
    }

    #[inline]
    pub fn remove_non_send<T: 'static>(&mut self) -> Option<T> {
        self.validate_non_send_access::<T>();
        // SAFE: we are on main thread
        unsafe { self.remove_resource_unchecked() }
    }

    #[inline]
    /// # Safety
    /// make sure you're on main thread if T isn't Send + Sync
    #[allow(unused_unsafe)]
    pub unsafe fn remove_resource_unchecked<T: 'static>(&mut self) -> Option<T> {
        let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
        let resource_archetype = self.archetypes.resource_mut();
        let unique_components = resource_archetype.unique_components_mut();
        let column = unique_components.get_mut(component_id)?;
        if column.is_empty() {
            return None;
        }
        // SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of the
        // ptr value / drop is called when T is dropped
        let (ptr, _) = unsafe { column.swap_remove_and_forget_unchecked(0) };
        // SAFE: column is of type T
        Some(unsafe { ptr.cast::<T>().read() })
    }

    /// Returns `true` if a resource of type `T` exists. Otherwise returns `false`.
    #[inline]
    pub fn contains_resource<T: Resource>(&self) -> bool {
        let component_id =
            if let Some(component_id) = self.components.get_resource_id(TypeId::of::<T>()) {
                component_id
            } else {
                return false;
            };
        self.get_populated_resource_column(component_id).is_some()
    }

    /// Gets a reference to the resource of the given type, if it exists. Otherwise returns [None]
    /// Resources are "unique" data of a given type.
    #[inline]
    pub fn get_resource<T: Resource>(&self) -> Option<&T> {
        let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
        unsafe { self.get_resource_with_id(component_id) }
    }

    pub fn is_resource_added<T: Resource>(&self) -> bool {
        let component_id =
            if let Some(component_id) = self.components.get_resource_id(TypeId::of::<T>()) {
                component_id
            } else {
                return false;
            };
        let column = if let Some(column) = self.get_populated_resource_column(component_id) {
            column
        } else {
            return false;
        };
        // SAFE: resources table always have row 0
        let ticks = unsafe { column.get_ticks_unchecked(0) };
        ticks.is_added(self.last_change_tick(), self.read_change_tick())
    }

    pub fn is_resource_changed<T: Resource>(&self) -> bool {
        let component_id =
            if let Some(component_id) = self.components.get_resource_id(TypeId::of::<T>()) {
                component_id
            } else {
                return false;
            };
        let column = if let Some(column) = self.get_populated_resource_column(component_id) {
            column
        } else {
            return false;
        };
        // SAFE: resources table always have row 0
        let ticks = unsafe { column.get_ticks_unchecked(0) };
        ticks.is_changed(self.last_change_tick(), self.read_change_tick())
    }

    /// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns
    /// [None] Resources are "unique" data of a given type.
    #[inline]
    pub fn get_resource_mut<T: Resource>(&mut self) -> Option<Mut<'_, T>> {
        // SAFE: unique world access
        unsafe { self.get_resource_unchecked_mut() }
    }

    // PERF: optimize this to avoid redundant lookups
    /// Gets a resource of type `T` if it exists, otherwise inserts the resource using the result of
    /// calling `func`.
    #[inline]
    pub fn get_resource_or_insert_with<T: Resource>(
        &mut self,
        func: impl FnOnce() -> T,
    ) -> Mut<'_, T> {
        if !self.contains_resource::<T>() {
            self.insert_resource(func());
        }
        self.get_resource_mut().unwrap()
    }

    /// Gets a mutable reference to the resource of the given type, if it exists. Otherwise returns
    /// [None] Resources are "unique" data of a given type.
    ///
    /// # Safety
    /// This will allow aliased mutable access to the given resource type. The caller must ensure
    /// that only one mutable access exists at a time.
    #[inline]
    pub unsafe fn get_resource_unchecked_mut<T: Resource>(&self) -> Option<Mut<'_, T>> {
        let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
        self.get_resource_unchecked_mut_with_id(component_id)
    }

    /// Gets a reference to the non-send resource of the given type, if it exists. Otherwise returns
    /// [None] Resources are "unique" data of a given type.
    #[inline]
    pub fn get_non_send_resource<T: 'static>(&self) -> Option<&T> {
        let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
        // SAFE: component id matches type T
        unsafe { self.get_non_send_with_id(component_id) }
    }

    /// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise
    /// returns [None] Resources are "unique" data of a given type.
    #[inline]
    pub fn get_non_send_resource_mut<T: 'static>(&mut self) -> Option<Mut<'_, T>> {
        // SAFE: unique world access
        unsafe { self.get_non_send_resource_unchecked_mut() }
    }

    /// Gets a mutable reference to the non-send resource of the given type, if it exists. Otherwise
    /// returns [None] Resources are "unique" data of a given type.
    ///
    /// # Safety
    /// This will allow aliased mutable access to the given non-send resource type. The caller must
    /// ensure that only one mutable access exists at a time.
    #[inline]
    pub unsafe fn get_non_send_resource_unchecked_mut<T: 'static>(&self) -> Option<Mut<'_, T>> {
        let component_id = self.components.get_resource_id(TypeId::of::<T>())?;
        self.get_non_send_unchecked_mut_with_id(component_id)
    }

    /// For a given batch of ([Entity], [Bundle]) pairs, either spawns each [Entity] with the given
    /// bundle (if the entity does not exist), or inserts the [Bundle] (if the entity already exists).
    /// This is faster than doing equivalent operations one-by-one.
    /// Returns [Ok] if all entities were successfully inserted into or spawned. Otherwise it returns an [Err]
    /// with a list of entities that could not be spawned or inserted into. A "spawn or insert" operation can
    /// only fail if an [Entity] is passed in with an "invalid generation" that conflicts with an existing [Entity].
    ///
    /// # Note
    /// Spawning a specific `entity` value is rarely the right choice. Most apps should use [`World::spawn_batch`].
    /// This method should generally only be used for sharing entities across apps, and only when they have a scheme
    /// worked out to share an ID space (which doesn't happen by default).
    ///
    /// ```
    /// use bevy_ecs::{entity::Entity, world::World, component::Component};
    /// #[derive(Component)]
    /// struct A(&'static str);
    /// #[derive(Component, PartialEq, Debug)]
    /// struct B(f32);
    ///
    /// let mut world = World::new();
    /// let e0 = world.spawn().id();
    /// let e1 = world.spawn().id();
    /// world.insert_or_spawn_batch(vec![
    ///   (e0, (A("a"), B(0.0))), // the first entity
    ///   (e1, (A("b"), B(1.0))), // the second entity
    /// ]);
    ///
    /// assert_eq!(world.get::<B>(e0), Some(&B(0.0)));
    /// ```
    pub fn insert_or_spawn_batch<I, B>(&mut self, iter: I) -> Result<(), Vec<Entity>>
    where
        I: IntoIterator,
        I::IntoIter: Iterator<Item = (Entity, B)>,
        B: Bundle,
    {
        self.flush();

        let iter = iter.into_iter();
        let change_tick = *self.change_tick.get_mut();

        let bundle_info = self
            .bundles
            .init_info::<B>(&mut self.components, &mut self.storages);
        enum SpawnOrInsert<'a, 'b> {
            Spawn(BundleSpawner<'a, 'b>),
            Insert(BundleInserter<'a, 'b>, ArchetypeId),
        }

        impl<'a, 'b> SpawnOrInsert<'a, 'b> {
            fn entities(&mut self) -> &mut Entities {
                match self {
                    SpawnOrInsert::Spawn(spawner) => spawner.entities,
                    SpawnOrInsert::Insert(inserter, _) => inserter.entities,
                }
            }
        }
        let mut spawn_or_insert = SpawnOrInsert::Spawn(bundle_info.get_bundle_spawner(
            &mut self.entities,
            &mut self.archetypes,
            &mut self.components,
            &mut self.storages,
            change_tick,
        ));

        let mut invalid_entities = Vec::new();
        for (entity, bundle) in iter {
            match spawn_or_insert
                .entities()
                .alloc_at_without_replacement(entity)
            {
                AllocAtWithoutReplacement::Exists(location) => {
                    match spawn_or_insert {
                        SpawnOrInsert::Insert(ref mut inserter, archetype)
                            if location.archetype_id == archetype =>
                        {
                            // SAFE: `entity` is valid, `location` matches entity, bundle matches inserter
                            unsafe { inserter.insert(entity, location.index, bundle) };
                        }
                        _ => {
                            let mut inserter = bundle_info.get_bundle_inserter(
                                &mut self.entities,
                                &mut self.archetypes,
                                &mut self.components,
                                &mut self.storages,
                                location.archetype_id,
                                change_tick,
                            );
                            // SAFE: `entity` is valid, `location` matches entity, bundle matches inserter
                            unsafe { inserter.insert(entity, location.index, bundle) };
                            spawn_or_insert =
                                SpawnOrInsert::Insert(inserter, location.archetype_id);
                        }
                    };
                }
                AllocAtWithoutReplacement::DidNotExist => {
                    match spawn_or_insert {
                        SpawnOrInsert::Spawn(ref mut spawner) => {
                            // SAFE: `entity` is allocated (but non existent), bundle matches inserter
                            unsafe { spawner.spawn_non_existent(entity, bundle) };
                        }
                        _ => {
                            let mut spawner = bundle_info.get_bundle_spawner(
                                &mut self.entities,
                                &mut self.archetypes,
                                &mut self.components,
                                &mut self.storages,
                                change_tick,
                            );
                            // SAFE: `entity` is valid, `location` matches entity, bundle matches inserter
                            unsafe { spawner.spawn_non_existent(entity, bundle) };
                            spawn_or_insert = SpawnOrInsert::Spawn(spawner);
                        }
                    };
                }
                AllocAtWithoutReplacement::ExistsWithWrongGeneration => {
                    invalid_entities.push(entity);
                }
            }
        }

        if invalid_entities.is_empty() {
            Ok(())
        } else {
            Err(invalid_entities)
        }
    }

    /// Temporarily removes the requested resource from this [World], then re-adds it before
    /// returning. This enables safe mutable access to a resource while still providing mutable
    /// world access
    /// ```
    /// use bevy_ecs::{component::Component, world::{World, Mut}};
    /// #[derive(Component)]
    /// struct A(u32);
    /// #[derive(Component)]
    /// struct B(u32);
    /// let mut world = World::new();
    /// world.insert_resource(A(1));
    /// let entity = world.spawn().insert(B(1)).id();
    ///
    /// world.resource_scope(|world, mut a: Mut<A>| {
    ///     let b = world.get_mut::<B>(entity).unwrap();
    ///     a.0 += b.0;
    /// });
    /// assert_eq!(world.get_resource::<A>().unwrap().0, 2);
    /// ```
    pub fn resource_scope<T: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<T>) -> U) -> U {
        let component_id = self
            .components
            .get_resource_id(TypeId::of::<T>())
            .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<T>()));
        let (ptr, mut ticks) = {
            let resource_archetype = self.archetypes.resource_mut();
            let unique_components = resource_archetype.unique_components_mut();
            let column = unique_components.get_mut(component_id).unwrap_or_else(|| {
                panic!("resource does not exist: {}", std::any::type_name::<T>())
            });
            if column.is_empty() {
                panic!("resource does not exist: {}", std::any::type_name::<T>());
            }
            // SAFE: if a resource column exists, row 0 exists as well. caller takes ownership of
            // the ptr value / drop is called when T is dropped
            unsafe { column.swap_remove_and_forget_unchecked(0) }
        };
        // SAFE: pointer is of type T
        let value = Mut {
            value: unsafe { &mut *ptr.cast::<T>() },
            ticks: Ticks {
                component_ticks: &mut ticks,
                last_change_tick: self.last_change_tick(),
                change_tick: self.change_tick(),
            },
        };
        let result = f(self, value);
        let resource_archetype = self.archetypes.resource_mut();
        let unique_components = resource_archetype.unique_components_mut();
        let column = unique_components
            .get_mut(component_id)
            .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::<T>()));
        unsafe {
            // SAFE: pointer is of type T
            column.push(ptr, ticks);
        }
        result
    }

    /// # Safety
    /// `component_id` must be assigned to a component of type T
    #[inline]
    pub(crate) unsafe fn get_resource_with_id<T: 'static>(
        &self,
        component_id: ComponentId,
    ) -> Option<&T> {
        let column = self.get_populated_resource_column(component_id)?;
        Some(&*column.get_data_ptr().as_ptr().cast::<T>())
    }

    /// # Safety
    /// `component_id` must be assigned to a component of type T.
    /// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
    #[inline]
    pub(crate) unsafe fn get_resource_unchecked_mut_with_id<T>(
        &self,
        component_id: ComponentId,
    ) -> Option<Mut<'_, T>> {
        let column = self.get_populated_resource_column(component_id)?;
        Some(Mut {
            value: &mut *column.get_data_ptr().cast::<T>().as_ptr(),
            ticks: Ticks {
                component_ticks: &mut *column.get_ticks_mut_ptr_unchecked(0),
                last_change_tick: self.last_change_tick(),
                change_tick: self.read_change_tick(),
            },
        })
    }

    /// # Safety
    /// `component_id` must be assigned to a component of type T
    #[inline]
    pub(crate) unsafe fn get_non_send_with_id<T: 'static>(
        &self,
        component_id: ComponentId,
    ) -> Option<&T> {
        self.validate_non_send_access::<T>();
        self.get_resource_with_id(component_id)
    }

    /// # Safety
    /// `component_id` must be assigned to a component of type T.
    /// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
    #[inline]
    pub(crate) unsafe fn get_non_send_unchecked_mut_with_id<T: 'static>(
        &self,
        component_id: ComponentId,
    ) -> Option<Mut<'_, T>> {
        self.validate_non_send_access::<T>();
        self.get_resource_unchecked_mut_with_id(component_id)
    }

    /// # Safety
    /// `component_id` must be valid and correspond to a resource component of type T
    #[inline]
    unsafe fn insert_resource_with_id<T>(&mut self, component_id: ComponentId, mut value: T) {
        let change_tick = self.change_tick();
        let column = self.initialize_resource_internal(component_id);
        if column.is_empty() {
            // SAFE: column is of type T and has been allocated above
            let data = (&mut value as *mut T).cast::<u8>();
            std::mem::forget(value);
            column.push(data, ComponentTicks::new(change_tick));
        } else {
            // SAFE: column is of type T and has already been allocated
            *column.get_data_unchecked(0).cast::<T>() = value;
            column.get_ticks_unchecked_mut(0).set_changed(change_tick);
        }
    }

    /// # Safety
    /// `component_id` must be valid and correspond to a resource component of type T
    #[inline]
    unsafe fn initialize_resource_internal(&mut self, component_id: ComponentId) -> &mut Column {
        // SAFE: resource archetype always exists
        let resource_archetype = self
            .archetypes
            .archetypes
            .get_unchecked_mut(ArchetypeId::RESOURCE.index());
        let resource_archetype_components = &mut resource_archetype.components;
        let archetype_component_count = &mut self.archetypes.archetype_component_count;
        let components = &self.components;
        resource_archetype
            .unique_components
            .get_or_insert_with(component_id, || {
                resource_archetype_components.insert(
                    component_id,
                    ArchetypeComponentInfo {
                        archetype_component_id: ArchetypeComponentId::new(
                            *archetype_component_count,
                        ),
                        storage_type: StorageType::Table,
                    },
                );
                *archetype_component_count += 1;
                let component_info = components.get_info_unchecked(component_id);
                Column::with_capacity(component_info, 1)
            })
    }

    pub(crate) fn initialize_resource<T: Resource>(&mut self) -> ComponentId {
        let component_id = self.components.init_resource::<T>();
        // SAFE: resource initialized above
        unsafe { self.initialize_resource_internal(component_id) };
        component_id
    }

    pub(crate) fn initialize_non_send_resource<T: 'static>(&mut self) -> ComponentId {
        let component_id = self.components.init_non_send::<T>();
        // SAFE: resource initialized above
        unsafe { self.initialize_resource_internal(component_id) };
        component_id
    }

    /// returns the resource column if the requested resource exists
    pub(crate) fn get_populated_resource_column(
        &self,
        component_id: ComponentId,
    ) -> Option<&Column> {
        let resource_archetype = self.archetypes.resource();
        let unique_components = resource_archetype.unique_components();
        unique_components.get(component_id).and_then(|column| {
            if column.is_empty() {
                None
            } else {
                Some(column)
            }
        })
    }

    pub(crate) fn validate_non_send_access<T: 'static>(&self) {
        if !self.main_thread_validator.is_main_thread() {
            panic!(
                "attempted to access NonSend resource {} off of the main thread",
                std::any::type_name::<T>()
            );
        }
    }

    /// Empties queued entities and adds them to the empty [Archetype].
    /// This should be called before doing operations that might operate on queued entities,
    /// such as inserting a [Component].
    pub(crate) fn flush(&mut self) {
        let empty_archetype = self.archetypes.empty_mut();
        unsafe {
            let table = &mut self.storages.tables[empty_archetype.table_id()];
            // PERF: consider pre-allocating space for flushed entities
            // SAFE: entity is set to a valid location
            self.entities.flush(|entity, location| {
                // SAFE: no components are allocated by archetype.allocate() because the archetype
                // is empty
                *location = empty_archetype.allocate(entity, table.allocate(entity));
            });
        }
    }

    #[inline]
    pub fn increment_change_tick(&self) -> u32 {
        self.change_tick.fetch_add(1, Ordering::AcqRel)
    }

    #[inline]
    pub fn read_change_tick(&self) -> u32 {
        self.change_tick.load(Ordering::Acquire)
    }

    #[inline]
    pub fn change_tick(&mut self) -> u32 {
        *self.change_tick.get_mut()
    }

    #[inline]
    pub fn last_change_tick(&self) -> u32 {
        self.last_change_tick
    }

    pub fn check_change_ticks(&mut self) {
        // Iterate over all component change ticks, clamping their age to max age
        // PERF: parallelize
        let change_tick = self.change_tick();
        self.storages.tables.check_change_ticks(change_tick);
        self.storages.sparse_sets.check_change_ticks(change_tick);
        let resource_archetype = self.archetypes.resource_mut();
        for column in resource_archetype.unique_components.values_mut() {
            column.check_change_ticks(change_tick);
        }
    }

    pub fn clear_entities(&mut self) {
        self.storages.tables.clear();
        self.storages.sparse_sets.clear();
        self.archetypes.clear_entities();
        self.entities.clear();
    }
}

impl fmt::Debug for World {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("World")
            .field("id", &self.id)
            .field("entity_count", &self.entities.len())
            .field("archetype_count", &self.archetypes.len())
            .field("component_count", &self.components.len())
            .field(
                "resource_count",
                &self.archetypes.resource().unique_components.len(),
            )
            .finish()
    }
}

unsafe impl Send for World {}
unsafe impl Sync for World {}

/// Creates `Self` using data from the given [World]
pub trait FromWorld {
    /// Creates `Self` using data from the given [World]
    fn from_world(world: &mut World) -> Self;
}

impl<T: Default> FromWorld for T {
    fn from_world(_world: &mut World) -> Self {
        T::default()
    }
}

struct MainThreadValidator {
    main_thread: std::thread::ThreadId,
}

impl MainThreadValidator {
    fn is_main_thread(&self) -> bool {
        self.main_thread == std::thread::current().id()
    }
}

impl Default for MainThreadValidator {
    fn default() -> Self {
        Self {
            main_thread: std::thread::current().id(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::World;
    use bevy_ecs_macros::Component;
    use std::{
        panic,
        sync::{
            atomic::{AtomicBool, Ordering},
            Arc, Mutex,
        },
    };

    // For bevy_ecs_macros
    use crate as bevy_ecs;

    type ID = u8;

    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    enum DropLogItem {
        Create(ID),
        Drop(ID),
    }

    #[derive(Component)]
    struct MayPanicInDrop {
        drop_log: Arc<Mutex<Vec<DropLogItem>>>,
        expected_panic_flag: Arc<AtomicBool>,
        should_panic: bool,
        id: u8,
    }

    impl MayPanicInDrop {
        fn new(
            drop_log: &Arc<Mutex<Vec<DropLogItem>>>,
            expected_panic_flag: &Arc<AtomicBool>,
            should_panic: bool,
            id: u8,
        ) -> Self {
            println!("creating component with id {}", id);
            drop_log.lock().unwrap().push(DropLogItem::Create(id));

            Self {
                drop_log: Arc::clone(drop_log),
                expected_panic_flag: Arc::clone(expected_panic_flag),
                should_panic,
                id,
            }
        }
    }

    impl Drop for MayPanicInDrop {
        fn drop(&mut self) {
            println!("dropping component with id {}", self.id);

            {
                let mut drop_log = self.drop_log.lock().unwrap();
                drop_log.push(DropLogItem::Drop(self.id));
                // Don't keep the mutex while panicking, or we'll poison it.
                drop(drop_log);
            }

            if self.should_panic {
                self.expected_panic_flag.store(true, Ordering::SeqCst);
                panic!("testing what happens on panic inside drop");
            }
        }
    }

    struct DropTestHelper {
        drop_log: Arc<Mutex<Vec<DropLogItem>>>,
        /// Set to `true` right before we intentionally panic, so that if we get
        /// a panic, we know if it was intended or not.
        expected_panic_flag: Arc<AtomicBool>,
    }

    impl DropTestHelper {
        pub fn new() -> Self {
            Self {
                drop_log: Arc::new(Mutex::new(Vec::<DropLogItem>::new())),
                expected_panic_flag: Arc::new(AtomicBool::new(false)),
            }
        }

        pub fn make_component(&self, should_panic: bool, id: ID) -> MayPanicInDrop {
            MayPanicInDrop::new(&self.drop_log, &self.expected_panic_flag, should_panic, id)
        }

        pub fn finish(self, panic_res: std::thread::Result<()>) -> Vec<DropLogItem> {
            let drop_log = Arc::try_unwrap(self.drop_log)
                .unwrap()
                .into_inner()
                .unwrap();
            let expected_panic_flag = self.expected_panic_flag.load(Ordering::SeqCst);

            if !expected_panic_flag {
                match panic_res {
                    Ok(()) => panic!("Expected a panic but it didn't happen"),
                    Err(e) => panic::resume_unwind(e),
                }
            }

            drop_log
        }
    }

    #[test]
    fn panic_while_overwriting_component() {
        let helper = DropTestHelper::new();

        let res = panic::catch_unwind(|| {
            let mut world = World::new();
            world
                .spawn()
                .insert(helper.make_component(true, 0))
                .insert(helper.make_component(false, 1));

            println!("Done inserting! Dropping world...");
        });

        let drop_log = helper.finish(res);

        assert_eq!(
            &*drop_log,
            [
                DropLogItem::Create(0),
                DropLogItem::Create(1),
                DropLogItem::Drop(0),
                DropLogItem::Drop(1)
            ]
        );
    }
}
