Expand description
Ergonomic smart-pointer-like access to Bevy ECS entities.
This crate provides two complementary approaches for accessing entity data with immutable-only semantics (functional programming style):
§Type Hierarchy
Entity (Bevy's raw type)
│
├── EntityHandle (newtype, safe, explicit world param)
│ └── .bind(world) → BoundEntity<'w> (scoped access)
│
└── WorldRef::entity() → EntityPtr (smart pointer, 'static world)§Choosing Between Types
| Type | Safety | Ergonomics | Use When |
|---|---|---|---|
EntityHandle | ✅ Fully safe | Explicit world param | Store in components |
BoundEntity<'w> | ✅ Fully safe | Scoped lifetime | Simple access, compiler-checked |
EntityPtr | ✅ Safe API* | No lifetime params | Tree/graph traversal, recursion |
*One internal unsafe hidden by WorldExt extension trait
Recommendation: Start with BoundEntity<'w>. Use EntityPtr when lifetime
annotations become cumbersome for complex traversal.
§Safe Approach: EntityHandle + BoundEntity
Use this when you want fully safe code with explicit world parameters:
use bevy_ecs::prelude::*;
use bevy_entity_ptr::{EntityHandle, BoundEntity};
#[derive(Component)]
struct Target(EntityHandle);
#[derive(Component)]
struct Name(&'static str);
fn my_system(world: &World, query: &Query<&Target>) {
// EntityHandle stores compactly in components
for target in query.iter() {
// Bind to world for fluent access
let bound = target.0.bind(world);
if let Some(name) = bound.get::<Name>() {
println!("Target: {}", name.0);
}
}
}§Ergonomic Approach: WorldExt + EntityPtr
Use this when you want fluent traversal without passing &World everywhere.
The WorldExt trait hides the internal unsafe, providing a clean API.
use bevy_ecs::prelude::*;
use bevy_entity_ptr::{WorldExt, EntityHandle};
#[derive(Component)]
struct Target(EntityHandle);
#[derive(Component)]
struct Name(&'static str);
fn traverse_system(world: &World) {
// No unsafe needed! WorldExt provides ergonomic access
for entity in world.iter_entities() {
let ptr = world.entity_ptr(entity.id());
// Follow references fluently
if let Some(target) = ptr.follow::<Target, _>(|t| t.0) {
if let Some(name) = target.get::<Name>() {
println!("Target: {}", name.0);
}
}
}
}§Thread Safety
| Type | Send | Sync | Notes |
|---|---|---|---|
EntityHandle | Yes | Yes | Safe to store in components |
BoundEntity | No | No | Borrows &World |
WorldRef | No | No | System-scoped only |
EntityPtr | No | No | System-scoped only |
§Feature Flags
nav-traits: EnablesHasParentandHasChildrentraits for parent/child navigation
§Design Principles
- Immutable only - No
get_mutvariants (functional style) - Single unsafe boundary - Only
WorldRef::new()is unsafe - Graceful stale handling - Despawned entities return
None, not UB - Zero-cost where possible -
#[repr(transparent)],#[inline],const fn
Structs§
- Bound
Entity - An entity bound to a world reference for fluent, scoped access.
- Bound
Entity Nav - Navigation wrapper for
BoundEntity, providing parent/children traversal. - Entity
Handle - A lightweight handle to an entity that can be stored in components.
- Entity
Ptr - An ergonomic smart pointer to an entity with embedded World reference.
- Entity
PtrNav - Navigation wrapper for
EntityPtr, providing parent/children traversal. - Entity
PtrNav Many - Many-navigation wrapper for
EntityPtr, for collecting multiple related entities. - World
Ref - A reference to a World with erased lifetime for ergonomic entity traversal.
Traits§
- World
Ext - Extension trait for
Worldproviding ergonomic entity access methods.