bevy_entity_ptr
Smart-pointer-like access to entities in bevy_ecs, a high-performance Entity Component System library. Immutable only, by design.
Why This Crate?
When working with entity relationships in ECS (parent/child hierarchies, linked structures, graphs), accessing related entities requires repeatedly passing &World through every function call. This crate provides two approaches that make entity traversal ergonomic:
| Type | Safety | Ergonomics | Use When |
|---|---|---|---|
EntityPtr |
Safe API* | No lifetime params | Graph traversal, recursion, deep chains |
BoundEntity<'w> |
Fully safe | Scoped lifetime | Simple access, compiler-checked lifetimes |
EntityHandle |
Fully safe | Explicit world param | Store in components |
*One internal unsafe hidden by the WorldExt extension trait — see Safety.
Installation
[]
= "0.6"
Quick Start
Import the WorldExt trait and use world.entity_ptr() — no unsafe needed:
use *;
use ;
;
;
// Follow a reference to a related entity — no &World parameter needed
// Usage: world.entity_ptr() creates an EntityPtr from any &World context
Recursive Traversal
EntityPtr carries its world reference internally, so recursive functions don't need a &World parameter:
use *;
use ;
;
;
;
// Find the root of a hierarchy — no &World parameter needed
// Sum a value across an entire subtree
Optional References
Use follow_opt when a reference component might be None:
use *;
use ;
;
;
Safety
The WorldExt::entity_ptr() method internally transmutes &World to &'static World so that EntityPtr can carry the world reference without a lifetime parameter. This is what makes the ergonomic API possible — but because the 'static lifetime is fabricated, the compiler cannot catch use-after-free on the world reference.
Sound within ECS systems: When called from a system with &World access, the world is guaranteed to outlive the system scope. EntityPtr is !Send, preventing escape to other threads. All operations are read-only.
Not sound in arbitrary code: Because EntityPtr holds a 'static reference internally, the compiler won't prevent you from using it after the World is dropped. This would be undefined behavior.
// GOOD: EntityPtr used within a function that borrows &World
// BAD: Do NOT do this — the 'static lifetime means the compiler won't stop you
For fully safe code with no soundness caveats, use EntityHandle and BoundEntity<'w> — they carry proper lifetime parameters and are checked by the compiler.
Fully Safe Alternative: EntityHandle + BoundEntity
If you prefer zero unsafe with compiler-verified lifetimes:
use *;
use ;
;
;
EntityHandle is Send + Sync, making it safe to store in components.
Mixed Usage
Store handles in components, convert to smart pointers for traversal:
use *;
use ;
// EntityHandle is Send + Sync — safe to store in components
;
Navigation Traits (Optional)
Enable the nav-traits feature for parent/child navigation helpers:
[]
= { = "0.6", = ["nav-traits"] }
Implement the traits on your components:
use *;
use ;
;
;
Thread Safety
| Type | Send | Sync | Notes |
|---|---|---|---|
EntityHandle |
Yes | Yes | Safe to store in components |
BoundEntity<'w> |
No | No | Borrows &World |
WorldRef |
No | No | System-scoped only |
EntityPtr |
No | No | System-scoped only |
Multiple read-only systems can use bevy_entity_ptr concurrently — the scheduler runs them in parallel when all systems only read.
Using EntityPtr in Collections
EntityPtr implements Eq and Hash (comparing entity ID only), enabling use in HashSet and HashMap:
use HashSet;
use *;
use ;
Stale Reference Handling
Both approaches gracefully handle despawned entities — returning None instead of undefined behavior:
use *;
use EntityHandle;
;
What This Crate Does NOT Support (By Design)
- Mutable access — Use the ECS's native APIs for mutations
- Despawning — Use
world.despawn()directly - Component insertion/removal — Use the ECS's native APIs
- Cross-scope storage of
EntityPtr— UseEntityHandleor rawEntityfor storage
Bevy Compatibility
bevy_entity_ptr |
Bevy |
|---|---|
| 0.6 | 0.18 |
| 0.5 | 0.18 |
| 0.4 | 0.17 |
| 0.3 | 0.16 |
| 0.2 | 0.15 |
| 0.1 | 0.15 |
Development
This crate is co-developed with Claude Code.
License
MIT