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
impl World
Sourcepub fn add_entity<E: Extractable>(&self, entity: E) -> EntityId
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.
pub fn add_entity_with_acquirable<E: Extractable>( &self, entity: E, ) -> (EntityId, Acquirable<E>)
Sourcepub fn add_entities<E: Extractable>(
&self,
entities: impl IntoIterator<Item = E>,
) -> Vec<EntityId>
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.
Sourcepub fn extract_component<T: 'static>(
&self,
entity_id: &EntityId,
) -> Result<Acquirable<T>, WorldError>
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);Sourcepub fn remove_entity(&self, entity_id: &EntityId) -> Result<(), WorldError>
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);Sourcepub fn try_remove_entities(
&self,
entity_ids: &[EntityId],
) -> Result<(), WorldError>
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"),
}Sourcepub fn remove_entities(&self, entity_ids: &[EntityId])
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);Sourcepub fn query<T: 'static>(&self) -> Vec<(EntityId, Acquirable<T>)>
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.
Sourcepub fn entity_count(&self) -> usize
pub fn entity_count(&self) -> usize
Get the number of entities in the world.
Sourcepub fn archetype_count(&self) -> usize
pub fn archetype_count(&self) -> usize
Get the number of archetypes in the world.
Sourcepub fn contains_entity(&self, entity_id: &EntityId) -> bool
pub fn contains_entity(&self, entity_id: &EntityId) -> bool
Check if an entity exists in the world.
Sourcepub fn clear(&self)
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.