World

Struct World 

Source
pub struct World { /* private fields */ }
Expand description

The central storage for all entities and their components.

Entities are organized into archetypes based on their structure for better performance.

§Thread Safety

World uses lock-free data structures (DashMap) and per-archetype RwLocks for efficient concurrent access. Multiple threads can:

  • Add entities to different archetypes in parallel
  • Query different archetypes in parallel
  • Query and add entities simultaneously (queries snapshot archetypes)

§Query Optimization

The World maintains a type index that maps component types to the archetypes that contain them. This eliminates the need to check all archetypes during queries, significantly improving performance when many archetypes exist.

Implementations§

Source§

impl World

Source

pub fn new() -> Self

Create a new empty world.

Source

pub fn add_entity<E: Extractable>(&self, entity: E) -> EntityId

Add an entity to the world.

Returns the ID assigned to the entity.

This method is thread-safe and can be called concurrently from multiple threads. Entities with different types can be added in parallel with minimal contention.

Source

pub fn add_entity_with_acquirable<E: Extractable>( &self, entity: E, ) -> (EntityId, Acquirable<E>)

Source

pub fn add_entities<E: Extractable>( &self, entities: impl IntoIterator<Item = E>, ) -> Vec<EntityId>

Add multiple entities to the world in batch.

Returns a Vec of EntityIds assigned to the entities in order.

This method is optimized for bulk insertion by:

  • Pre-allocating entity IDs in a single atomic operation
  • Getting the archetype once for all entities
  • Minimizing index update overhead
§Performance

For adding many entities of the same type, this method is significantly faster than calling add_entity() repeatedly due to reduced atomic operations and archetype lookups.

§Thread Safety

This method is thread-safe and can be called concurrently from multiple threads.

Source

pub fn extract_component<T: 'static>( &self, entity_id: &EntityId, ) -> Result<Acquirable<T>, WorldError>

Extract a specific component from an entity.

Returns Ok(Acquirable<T>) if the component was found. Returns Err(WorldError::EntityNotFound) if the entity doesn’t exist. Returns Err(WorldError::ComponentNotFound) if the component type doesn’t exist on the entity.

§Example
use structecs::*;

#[derive(Debug, Extractable)]
struct Entity {
    name: String,
}

#[derive(Debug, Extractable)]
#[extractable(entity)]
struct Player {
    entity: Entity,
    health: u32,
}

let world = World::new();
let player_id = world.add_entity(Player {
    entity: Entity { name: "Alice".to_string() },
    health: 100,
});

// Extract the Entity component from Player
let entity = world.extract_component::<Entity>(&player_id).unwrap();
assert_eq!(entity.name, "Alice");

// Extract the whole Player
let player = world.extract_component::<Player>(&player_id).unwrap();
assert_eq!(player.health, 100);
Source

pub fn remove_entity(&self, entity_id: &EntityId) -> Result<(), WorldError>

Remove an entity from the world.

Returns Ok(()) if the entity was removed successfully. Returns Err(WorldError::EntityNotFound) if the entity doesn’t exist.

This method is thread-safe and can be called concurrently from multiple threads.

§Errors

Returns WorldError::EntityNotFound if the entity doesn’t exist in the world.

§Example
use structecs::*;

#[derive(Debug, Extractable)]
struct Player {
    name: String,
    health: u32,
}

let world = World::new();
let player_id = world.add_entity(Player {
    name: "Alice".to_string(),
    health: 100,
});

assert_eq!(world.entity_count(), 1);

// Remove the entity
world.remove_entity(&player_id).unwrap();
assert_eq!(world.entity_count(), 0);
Source

pub fn try_remove_entities( &self, entity_ids: &[EntityId], ) -> Result<(), WorldError>

Remove multiple entities from the world in batch.

Returns Ok(()) if all entities were removed successfully. Returns Err(WorldError::PartialRemoval) if some entities failed to remove. Non-existent entities are treated as failures.

This method is optimized for bulk deletion by:

  • Grouping entities by archetype to minimize archetype lookups
  • Batch-removing entities from each archetype
§Performance

For removing many entities, this method is more efficient than calling remove_entity() repeatedly because it processes entities in archetype groups, reducing overhead.

If you don’t need error tracking and want to avoid allocations, use remove_entities() instead.

§Thread Safety

This method is thread-safe and can be called concurrently from multiple threads.

§Errors

Returns WorldError::PartialRemoval with information about which entities were successfully removed and which failed.

§Example
use structecs::{*, WorldError};

#[derive(Debug, Extractable)]
struct Player {
    name: String,
    health: u32,
}

let world = World::new();

// Add multiple players
let mut ids = vec![];
for i in 0..5 {
    let id = world.add_entity(Player {
        name: format!("Player{}", i),
        health: 100,
});
    ids.push(id);
}

assert_eq!(world.entity_count(), 5);

// Remove first 3 entities
world.try_remove_entities(&ids[0..3]).unwrap();
assert_eq!(world.entity_count(), 2);

// Try to remove with non-existent entity
let mixed_ids = vec![ids[3], EntityId::from_raw(9999)];
match world.try_remove_entities(&mixed_ids) {
    Err(WorldError::PartialRemoval { succeeded, failed }) => {
        assert_eq!(succeeded.len(), 1);
        assert_eq!(failed.len(), 1);
    }
    _ => panic!("Expected PartialRemoval error"),
}
Source

pub fn remove_entities(&self, entity_ids: &[EntityId])

Remove multiple entities from the world in batch without error tracking.

This is a zero-allocation variant of try_remove_entities() that silently skips non-existent entities. Use this method when you don’t need to know which entities failed to remove and want maximum performance.

§Performance

This method is more efficient than try_remove_entities() because it:

  • Does not allocate vectors to track succeeded/failed entities
  • Groups entities by archetype to minimize archetype lookups
  • Silently skips non-existent entities without error tracking overhead

For bulk deletions where you don’t care about individual failures, this method provides the best performance.

§Thread Safety

This method is thread-safe and can be called concurrently from multiple threads.

§Example
use structecs::*;

#[derive(Debug, Extractable)]
struct Player {
    name: String,
    health: u32,
}

let world = World::new();

// Add multiple players
let mut ids = vec![];
for i in 0..10 {
    let id = world.add_entity(Player {
        name: format!("Player{}", i),
        health: 100,
    });
    ids.push(id);
}

assert_eq!(world.entity_count(), 10);

// Fast batch removal - silently skips non-existent entities
ids.push(EntityId::from_raw(9999)); // Add non-existent ID
world.remove_entities(&ids);

// All valid entities removed, invalid ones silently skipped
assert_eq!(world.entity_count(), 0);
Source

pub fn query<T: 'static>(&self) -> Vec<(EntityId, Acquirable<T>)>

Query all entities with component T.

Returns a Vec of (EntityId, Acquirable<T>) pairs.

§Example
use structecs::*;

#[derive(Debug, Extractable)]
struct Player {
    name: String,
    health: u32,
}

let world = World::new();

// Add multiple players
for i in 0..5 {
    world.add_entity(Player {
        name: format!("Player{}", i),
        health: 100,
    });
}

// Query for all Player entities
let players = world.query::<Player>();
assert_eq!(players.len(), 5);

// Direct iteration
for (id, player) in world.query::<Player>() {
    assert_eq!(player.health, 100);
}
§Performance

This method uses a type index to avoid checking all archetypes. Only archetypes that are known to contain type T are queried.

Performance improvements:

  • Type index lookup: O(1) instead of O(all archetypes)
  • Pre-allocated capacity based on matching archetype count
  • Single allocation with efficient extend operations

When there are many archetypes (100+), this can provide 5-10x speedup compared to checking all archetypes.

§Concurrency

Multiple threads can call this method simultaneously. Each archetype is locked independently and briefly, minimizing contention.

Source

pub fn entity_count(&self) -> usize

Get the number of entities in the world.

Source

pub fn archetype_count(&self) -> usize

Get the number of archetypes in the world.

Source

pub fn contains_entity(&self, entity_id: &EntityId) -> bool

Check if an entity exists in the world.

Source

pub fn clear(&self)

Remove all entities from the world.

This method clears all entities, archetypes, and the type index, resetting the world to an empty state. The entity ID counter is NOT reset.

§Thread Safety

This method is thread-safe but should typically be called when no other operations are in progress for best performance.

Trait Implementations§

Source§

impl Default for World

Source§

fn default() -> World

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !Freeze for World

§

impl !RefUnwindSafe for World

§

impl Send for World

§

impl Sync for World

§

impl Unpin for World

§

impl !UnwindSafe for World

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.