Skip to main content

Crate bevy_entity_ptr

Crate bevy_entity_ptr 

Source
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

TypeSafetyErgonomicsUse When
EntityHandle✅ Fully safeExplicit world paramStore in components
BoundEntity<'w>✅ Fully safeScoped lifetimeSimple access, compiler-checked
EntityPtr✅ Safe API*No lifetime paramsTree/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);

// BoundEntity provides fluent access with explicit world parameter
fn get_target_name<'w>(entity: Entity, world: &'w World) -> Option<&'w str> {
    let bound = EntityHandle::new(entity).bind(world);
    let target = bound.follow::<Target, _>(|t| t.0)?;
    target.get::<Name>().map(|n| n.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, EntityPtr, EntityHandle};

#[derive(Component)]
struct Target(EntityHandle);

#[derive(Component)]
struct Name(&'static str);

// EntityPtr carries its world reference — no &World threading needed
fn get_target_name(ptr: EntityPtr) -> Option<&'static str> {
    let target = ptr.follow::<Target, _>(|t| t.0)?;
    target.get::<Name>().map(|n| n.0)
}

// Usage: world.entity_ptr(entity) creates an EntityPtr
fn example(world: &World, entity: Entity) {
    let ptr = world.entity_ptr(entity);
    if let Some(name) = get_target_name(ptr) {
        println!("Target: {}", name);
    }
}

§Thread Safety

TypeSendSyncNotes
EntityHandleYesYesSafe to store in components
BoundEntityNoNoBorrows &World
WorldRefNoNoSystem-scoped only
EntityPtrNoNoSystem-scoped only

§Feature Flags

  • nav-traits: Enables HasParent and HasChildren traits for parent/child navigation

§Design Principles

  1. Immutable only - No get_mut variants (functional style)
  2. Single unsafe boundary - Only WorldRef::new() is unsafe
  3. Graceful stale handling - Despawned entities return None, not UB
  4. Zero-cost where possible - #[repr(transparent)], #[inline], const fn

§Safety

The WorldExt::entity_ptr() method internally transmutes &World to &'static World so that EntityPtr can carry the world reference without a lifetime parameter. Because the 'static lifetime is fabricated, the compiler cannot catch use-after-free on the world reference.

This is sound within Bevy systems because:

  • &World is guaranteed to outlive the system scope
  • EntityPtr is !Send, so it cannot escape to other threads
  • The World cannot be mutated while a system holds &World

This is NOT sound in arbitrary code where a World could be dropped while EntityPtr instances still exist — the fabricated 'static lifetime means the compiler won’t prevent this. If you use WorldExt::entity_ptr() outside of a Bevy system, you must ensure the World outlives all EntityPtr instances created from it.

For fully safe code with no soundness caveats, use EntityHandle and BoundEntity instead — they carry proper lifetime parameters.

Structs§

BoundEntity
An entity bound to a world reference for fluent, scoped access.
BoundEntityNav
Navigation wrapper for BoundEntity, providing parent/children traversal.
EntityHandle
A lightweight handle to an entity that can be stored in components.
EntityPtr
An ergonomic smart pointer to an entity with embedded World reference.
EntityPtrNav
Navigation wrapper for EntityPtr, providing parent/children traversal.
EntityPtrNavMany
Many-navigation wrapper for EntityPtr, for collecting multiple related entities.
WorldRef
A reference to a World with erased lifetime for ergonomic entity traversal.

Traits§

HasChildren
Trait for components that reference child entities.
HasParent
Trait for components that reference a parent entity.
WorldExt
Extension trait for World providing ergonomic entity access methods.