Skip to main content

EntityHandle

Struct EntityHandle 

Source
pub struct EntityHandle(/* private fields */);
Expand description

A lightweight handle to an entity that can be stored in components.

This is a newtype over Bevy’s Entity that provides ergonomic access methods while requiring explicit &World parameters. Safe to store and share across threads.

§Size

8 bytes (same as Entity)

§Thread Safety

Send + Sync - safe to store in components and share between threads.

Implementations§

Source§

impl EntityHandle

Source

pub const fn new(entity: Entity) -> Self

Creates a new handle from an entity.

Examples found in repository?
examples/tree_traversal.rs (line 92)
75fn main() {
76    let mut world = World::new();
77
78    // Build a tree:
79    //
80    //           root (10)
81    //          /    \
82    //       a (5)   b (3)
83    //         |
84    //       c (2)
85    //         |
86    //       d (7)
87    //
88    println!("Building tree structure...\n");
89
90    let d = world.spawn((Name("d"), Value(7))).id();
91    let c = world
92        .spawn((Name("c"), Value(2), Children(vec![EntityHandle::new(d)])))
93        .id();
94    // Add parent link to d
95    world.entity_mut(d).insert(Parent(EntityHandle::new(c)));
96
97    let a = world
98        .spawn((Name("a"), Value(5), Children(vec![EntityHandle::new(c)])))
99        .id();
100    world.entity_mut(c).insert(Parent(EntityHandle::new(a)));
101
102    let b = world.spawn((Name("b"), Value(3))).id();
103
104    let root = world
105        .spawn((
106            Name("root"),
107            Value(10),
108            Children(vec![EntityHandle::new(a), EntityHandle::new(b)]),
109        ))
110        .id();
111    world.entity_mut(a).insert(Parent(EntityHandle::new(root)));
112    world.entity_mut(b).insert(Parent(EntityHandle::new(root)));
113
114    // No unsafe needed! WorldExt provides ergonomic access
115    // Demonstrate tree operations
116    let root_ptr = world.entity_ptr(root);
117
118    // 1. Sum all values
119    let total = sum_tree(root_ptr);
120    println!("Sum of all values in tree: {}", total);
121    println!("  Expected: 10 + 5 + 2 + 7 + 3 = 27");
122    assert_eq!(total, 27);
123
124    // 2. Find root from any node
125    let d_ptr = world.entity_ptr(d);
126    let found_root = find_root(d_ptr);
127    let root_name = found_root.get::<Name>().unwrap().0;
128    println!("\nFinding root from node 'd': {}", root_name);
129    assert_eq!(root_name, "root");
130
131    let b_ptr = world.entity_ptr(b);
132    let found_root = find_root(b_ptr);
133    let root_name = found_root.get::<Name>().unwrap().0;
134    println!("Finding root from node 'b': {}", root_name);
135    assert_eq!(root_name, "root");
136
137    // 3. Compute tree depth (number of edges on longest path)
138    let depth = tree_depth(root_ptr);
139    println!("\nTree depth from root: {}", depth);
140    println!("  Expected: 3 (root->a, a->c, c->d = 3 edges)");
141    assert_eq!(depth, 3);
142
143    let a_ptr = world.entity_ptr(a);
144    let a_depth = tree_depth(a_ptr);
145    println!("Subtree depth from 'a': {}", a_depth);
146    assert_eq!(a_depth, 2);
147
148    // 4. Collect all names in pre-order traversal
149    let mut names = Vec::new();
150    collect_names(root_ptr, &mut names);
151    println!("\nPre-order traversal: {:?}", names);
152    assert_eq!(names, vec!["root", "a", "c", "d", "b"]);
153
154    println!("\nAll assertions passed!");
155}
More examples
Hide additional examples
examples/concurrent_systems.rs (line 116)
95fn main() {
96    let mut world = World::new();
97
98    // Build two separate hierarchies:
99    //
100    // Squad Alpha:           Squad Beta:
101    //   alpha (H:100, A:50)    beta (H:80, A:30)
102    //    ├─ a1 (H:50, A:20)     ├─ b1 (H:40, A:15)
103    //    └─ a2 (H:50, A:20)     └─ b2 (H:40, A:15)
104    //
105    println!("Building entity hierarchies...\n");
106
107    // Build Squad Alpha
108    let a1 = world.spawn((Name("a1"), Health(50), Armor(20))).id();
109    let a2 = world.spawn((Name("a2"), Health(50), Armor(20))).id();
110    let alpha = world
111        .spawn((
112            Name("Squad Alpha"),
113            Health(100),
114            Armor(50),
115            RootMarker,
116            Children(vec![EntityHandle::new(a1), EntityHandle::new(a2)]),
117        ))
118        .id();
119
120    // Build Squad Beta
121    let b1 = world.spawn((Name("b1"), Health(40), Armor(15))).id();
122    let b2 = world.spawn((Name("b2"), Health(40), Armor(15))).id();
123    let _beta = world
124        .spawn((
125            Name("Squad Beta"),
126            Health(80),
127            Armor(30),
128            RootMarker,
129            Children(vec![EntityHandle::new(b1), EntityHandle::new(b2)]),
130        ))
131        .id();
132
133    // In a real Bevy application, you would add systems like this:
134    //
135    //   app.add_systems(Update, (compute_health_system, compute_armor_system));
136    //
137    // Bevy's scheduler would automatically run them in parallel because
138    // both systems only have `&World` access (no exclusive/mutable access).
139
140    println!("Simulating concurrent system execution:\n");
141    println!("(In a real Bevy app, these would run in parallel)\n");
142
143    // Create a schedule and add both systems
144    let mut schedule = Schedule::default();
145    schedule.add_systems((compute_health_system, compute_armor_system));
146
147    // Run the schedule - systems execute (potentially in parallel with multi-threading)
148    schedule.run(&mut world);
149
150    // Verify the computed values
151    println!("\n--- Verification ---");
152
153    let alpha_ptr = world.entity_ptr(alpha);
154
155    let alpha_health = sum_health(alpha_ptr);
156    let alpha_armor = sum_armor(alpha_ptr);
157
158    println!(
159        "Squad Alpha: health={}, armor={}",
160        alpha_health, alpha_armor
161    );
162    assert_eq!(alpha_health, 200); // 100 + 50 + 50
163    assert_eq!(alpha_armor, 90); // 50 + 20 + 20
164
165    println!("\nAll assertions passed!");
166    println!("\nKey takeaway: Use world.entity_ptr() in each system.");
167    println!("EntityPtr is NOT shared between systems - each system has");
168    println!("independent instances that are safe for concurrent reads.");
169}
examples/entity_graph.rs (line 131)
106fn main() {
107    let mut world = World::new();
108
109    println!("Setting up game entities...\n");
110
111    // Create some items
112    let sword = world
113        .spawn((Name("Iron Sword"), Weight(5.0), Damage(15)))
114        .id();
115    let shield = world
116        .spawn((Name("Wooden Shield"), Weight(8.0), Defense(10)))
117        .id();
118    let potion = world.spawn((Name("Health Potion"), Weight(0.5))).id();
119    let gold = world.spawn((Name("Gold Coins"), Weight(1.0))).id();
120    let bow = world
121        .spawn((Name("Short Bow"), Weight(3.0), Damage(10)))
122        .id();
123
124    // Create the hero
125    let hero = world
126        .spawn((
127            Name("Hero"),
128            Health(100),
129            Target(None), // Not targeting anyone yet
130            Inventory(vec![
131                EntityHandle::new(sword),
132                EntityHandle::new(shield),
133                EntityHandle::new(potion),
134                EntityHandle::new(gold),
135            ]),
136            Equipped {
137                weapon: Some(EntityHandle::new(sword)),
138                armor: Some(EntityHandle::new(shield)),
139            },
140        ))
141        .id();
142
143    // Create an enemy targeting the hero
144    let goblin = world
145        .spawn((
146            Name("Goblin"),
147            Health(30),
148            Target(Some(EntityHandle::new(hero))),
149            Inventory(vec![EntityHandle::new(bow)]),
150            Equipped {
151                weapon: Some(EntityHandle::new(bow)),
152                armor: None,
153            },
154        ))
155        .id();
156
157    // Create another enemy also targeting the hero
158    let _orc = world
159        .spawn((
160            Name("Orc"),
161            Health(50),
162            Target(Some(EntityHandle::new(hero))),
163        ))
164        .id();
165
166    // Demonstrate entity graph queries
167    let hero_ptr = world.entity_ptr(hero);
168    let goblin_ptr = world.entity_ptr(goblin);
169
170    // 1. Calculate inventory weight
171    let weight = total_weight(hero_ptr);
172    println!("Hero's inventory weight: {} lbs", weight);
173    println!("  Expected: 5.0 + 8.0 + 0.5 + 1.0 = 14.5");
174    assert!((weight - 14.5).abs() < 0.01);
175
176    // 2. Check equipped items
177    let damage = equipped_damage(hero_ptr);
178    println!("\nHero's equipped weapon damage: {:?}", damage);
179    assert_eq!(damage, Some(15));
180
181    let defense = equipped_defense(hero_ptr);
182    println!("Hero's equipped armor defense: {:?}", defense);
183    assert_eq!(defense, Some(10));
184
185    // 3. Goblin's equipment
186    let goblin_damage = equipped_damage(goblin_ptr);
187    println!("\nGoblin's equipped weapon damage: {:?}", goblin_damage);
188    assert_eq!(goblin_damage, Some(10));
189
190    let goblin_defense = equipped_defense(goblin_ptr);
191    println!("Goblin's equipped armor defense: {:?}", goblin_defense);
192    assert_eq!(goblin_defense, None); // No armor equipped
193
194    // 4. Check targeting
195    let hero_target = target_info(hero_ptr);
196    println!("\nHero's target: {:?}", hero_target);
197    assert_eq!(hero_target, None);
198
199    let goblin_target = target_info(goblin_ptr);
200    println!("Goblin's target: {:?}", goblin_target);
201    assert_eq!(goblin_target, Some(("Hero", 100)));
202
203    // 5. Find all entities targeting the hero
204    let attackers = find_attackers(&world, hero);
205    let attacker_names: Vec<_> = attackers
206        .iter()
207        .filter_map(|p| p.get::<Name>())
208        .map(|n| n.0)
209        .collect();
210    println!("\nEntities targeting the hero: {:?}", attacker_names);
211    assert_eq!(attacker_names.len(), 2);
212    assert!(attacker_names.contains(&"Goblin"));
213    assert!(attacker_names.contains(&"Orc"));
214
215    // 6. Update hero's target to the goblin
216    world
217        .entity_mut(hero)
218        .insert(Target(Some(EntityHandle::new(goblin))));
219
220    // Re-query with fresh EntityPtr
221    let hero_ptr = world.entity_ptr(hero);
222
223    let hero_target = target_info(hero_ptr);
224    println!("\nAfter targeting goblin:");
225    println!("Hero's target: {:?}", hero_target);
226    assert_eq!(hero_target, Some(("Goblin", 30)));
227
228    println!("\nAll assertions passed!");
229}
examples/mixed_usage.rs (line 99)
86fn main() {
87    let mut world = World::new();
88
89    println!("=== Mixed Usage Example ===\n");
90
91    // Build a linked list: a -> b -> c -> d
92    println!("Building linked list: a -> b -> c -> d\n");
93
94    let d = world.spawn((Name("d"), LinkedList { next: None })).id();
95    let c = world
96        .spawn((
97            Name("c"),
98            LinkedList {
99                next: Some(EntityHandle::new(d)),
100            },
101        ))
102        .id();
103    let b = world
104        .spawn((
105            Name("b"),
106            LinkedList {
107                next: Some(EntityHandle::new(c)),
108            },
109        ))
110        .id();
111    let a = world
112        .spawn((
113            Name("a"),
114            LinkedList {
115                next: Some(EntityHandle::new(b)),
116            },
117        ))
118        .id();
119
120    // Store handle for later use (EntityHandle is Send + Sync)
121    let a_handle = EntityHandle::new(a);
122
123    // === BoundEntity approach ===
124    println!("--- BoundEntity Approach (explicit &World) ---");
125
126    let bound = a_handle.bind(&world);
127    let length = count_chain_length_bound(bound);
128    println!("Chain length from 'a': {}", length);
129    assert_eq!(length, 4);
130
131    // Get component with explicit world
132    let name = a_handle.get::<Name>(&world).unwrap().0;
133    println!("Starting node name: {}", name);
134
135    // === EntityPtr approach ===
136    println!("\n--- EntityPtr Approach (ergonomic) ---");
137
138    // No unsafe needed! WorldExt provides ergonomic access
139    let ptr = world.entity_ptr(a_handle.entity()); // Convert handle to ptr
140
141    let length = count_chain_length_ptr(ptr);
142    println!("Chain length from 'a': {}", length);
143    assert_eq!(length, 4);
144
145    // Convert back to handle
146    let back_to_handle = ptr.handle();
147    assert_eq!(back_to_handle.entity(), a_handle.entity());
148    println!("Round-trip handle conversion: OK");
149
150    // === Team example ===
151    println!("\n--- Team Example ---");
152
153    // Create team members
154    let alice = world.spawn((Name("Alice"), Health(100))).id();
155    let bob = world.spawn((Name("Bob"), Health(80))).id();
156    let charlie = world.spawn((Name("Charlie"), Health(120))).id();
157
158    // Create team leader with team
159    let leader = world
160        .spawn((
161            Name("Leader"),
162            Health(150),
163            Team(vec![
164                EntityHandle::new(alice),
165                EntityHandle::new(bob),
166                EntityHandle::new(charlie),
167            ]),
168        ))
169        .id();
170
171    // Calculate total team health using EntityPtr
172    let leader_ptr = world.entity_ptr(leader);
173    let total = team_health(leader_ptr);
174    println!("Total team health: {}", total);
175    println!("  Expected: 150 + 100 + 80 + 120 = 450");
176    assert_eq!(total, 450);
177
178    // Find team member using BoundEntity
179    let leader_bound = EntityHandle::new(leader).bind(&world);
180    let bob_bound = find_team_member(leader_bound, "Bob").unwrap();
181    let bob_health = bob_bound.get::<Health>().unwrap().0;
182    println!("Bob's health: {}", bob_health);
183    assert_eq!(bob_health, 80);
184
185    // === Stale Reference Handling ===
186    println!("\n--- Stale Reference Handling ---");
187
188    let temp = world.spawn((Name("Temporary"), Health(50))).id();
189    let temp_handle = EntityHandle::new(temp);
190
191    // Check it's alive
192    println!("Before despawn:");
193    println!("  is_alive: {}", temp_handle.is_alive(&world));
194    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
195    assert!(temp_handle.is_alive(&world));
196
197    // Despawn the entity
198    world.despawn(temp);
199
200    // Handle gracefully returns None
201    println!("After despawn:");
202    println!("  is_alive: {}", temp_handle.is_alive(&world));
203    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
204    assert!(!temp_handle.is_alive(&world));
205    assert!(temp_handle.get::<Name>(&world).is_none());
206
207    // === Mixing approaches in computation ===
208    println!("\n--- Mixing Approaches ---");
209
210    // Start with a stored handle
211    let leader_handle = EntityHandle::new(leader);
212
213    // Use BoundEntity for one part of the computation
214    let bound = leader_handle.bind(&world);
215    let leader_name = bound.get::<Name>().unwrap().0;
216
217    // Switch to EntityPtr for another part
218    let ptr = world.entity_ptr(leader_handle.entity());
219    let total_health = team_health(ptr);
220
221    println!(
222        "{}'s team has total health of {}",
223        leader_name, total_health
224    );
225
226    // Can also convert EntityPtr back to BoundEntity's handle
227    let ptr_handle = ptr.handle();
228    let rebound = ptr_handle.bind(&world);
229    assert_eq!(rebound.get::<Name>().unwrap().0, leader_name);
230    println!("Seamless conversion between approaches: OK");
231
232    println!("\nAll assertions passed!");
233}
Source

pub const fn entity(self) -> Entity

Returns the underlying Entity.

Examples found in repository?
examples/entity_graph.rs (line 99)
90fn find_attackers(world: &World, target_entity: Entity) -> Vec<EntityPtr> {
91    world
92        .iter_entities()
93        .filter_map(|entity_ref| {
94            let entity = entity_ref.id();
95            let ptr = world.entity_ptr(entity);
96
97            // Check if this entity has a Target component pointing to our target
98            ptr.get::<Target>().and_then(|t| {
99                t.0.filter(|h| h.entity() == target_entity)
100                    .map(|_| world.entity_ptr(entity))
101            })
102        })
103        .collect()
104}
More examples
Hide additional examples
examples/mixed_usage.rs (line 139)
86fn main() {
87    let mut world = World::new();
88
89    println!("=== Mixed Usage Example ===\n");
90
91    // Build a linked list: a -> b -> c -> d
92    println!("Building linked list: a -> b -> c -> d\n");
93
94    let d = world.spawn((Name("d"), LinkedList { next: None })).id();
95    let c = world
96        .spawn((
97            Name("c"),
98            LinkedList {
99                next: Some(EntityHandle::new(d)),
100            },
101        ))
102        .id();
103    let b = world
104        .spawn((
105            Name("b"),
106            LinkedList {
107                next: Some(EntityHandle::new(c)),
108            },
109        ))
110        .id();
111    let a = world
112        .spawn((
113            Name("a"),
114            LinkedList {
115                next: Some(EntityHandle::new(b)),
116            },
117        ))
118        .id();
119
120    // Store handle for later use (EntityHandle is Send + Sync)
121    let a_handle = EntityHandle::new(a);
122
123    // === BoundEntity approach ===
124    println!("--- BoundEntity Approach (explicit &World) ---");
125
126    let bound = a_handle.bind(&world);
127    let length = count_chain_length_bound(bound);
128    println!("Chain length from 'a': {}", length);
129    assert_eq!(length, 4);
130
131    // Get component with explicit world
132    let name = a_handle.get::<Name>(&world).unwrap().0;
133    println!("Starting node name: {}", name);
134
135    // === EntityPtr approach ===
136    println!("\n--- EntityPtr Approach (ergonomic) ---");
137
138    // No unsafe needed! WorldExt provides ergonomic access
139    let ptr = world.entity_ptr(a_handle.entity()); // Convert handle to ptr
140
141    let length = count_chain_length_ptr(ptr);
142    println!("Chain length from 'a': {}", length);
143    assert_eq!(length, 4);
144
145    // Convert back to handle
146    let back_to_handle = ptr.handle();
147    assert_eq!(back_to_handle.entity(), a_handle.entity());
148    println!("Round-trip handle conversion: OK");
149
150    // === Team example ===
151    println!("\n--- Team Example ---");
152
153    // Create team members
154    let alice = world.spawn((Name("Alice"), Health(100))).id();
155    let bob = world.spawn((Name("Bob"), Health(80))).id();
156    let charlie = world.spawn((Name("Charlie"), Health(120))).id();
157
158    // Create team leader with team
159    let leader = world
160        .spawn((
161            Name("Leader"),
162            Health(150),
163            Team(vec![
164                EntityHandle::new(alice),
165                EntityHandle::new(bob),
166                EntityHandle::new(charlie),
167            ]),
168        ))
169        .id();
170
171    // Calculate total team health using EntityPtr
172    let leader_ptr = world.entity_ptr(leader);
173    let total = team_health(leader_ptr);
174    println!("Total team health: {}", total);
175    println!("  Expected: 150 + 100 + 80 + 120 = 450");
176    assert_eq!(total, 450);
177
178    // Find team member using BoundEntity
179    let leader_bound = EntityHandle::new(leader).bind(&world);
180    let bob_bound = find_team_member(leader_bound, "Bob").unwrap();
181    let bob_health = bob_bound.get::<Health>().unwrap().0;
182    println!("Bob's health: {}", bob_health);
183    assert_eq!(bob_health, 80);
184
185    // === Stale Reference Handling ===
186    println!("\n--- Stale Reference Handling ---");
187
188    let temp = world.spawn((Name("Temporary"), Health(50))).id();
189    let temp_handle = EntityHandle::new(temp);
190
191    // Check it's alive
192    println!("Before despawn:");
193    println!("  is_alive: {}", temp_handle.is_alive(&world));
194    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
195    assert!(temp_handle.is_alive(&world));
196
197    // Despawn the entity
198    world.despawn(temp);
199
200    // Handle gracefully returns None
201    println!("After despawn:");
202    println!("  is_alive: {}", temp_handle.is_alive(&world));
203    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
204    assert!(!temp_handle.is_alive(&world));
205    assert!(temp_handle.get::<Name>(&world).is_none());
206
207    // === Mixing approaches in computation ===
208    println!("\n--- Mixing Approaches ---");
209
210    // Start with a stored handle
211    let leader_handle = EntityHandle::new(leader);
212
213    // Use BoundEntity for one part of the computation
214    let bound = leader_handle.bind(&world);
215    let leader_name = bound.get::<Name>().unwrap().0;
216
217    // Switch to EntityPtr for another part
218    let ptr = world.entity_ptr(leader_handle.entity());
219    let total_health = team_health(ptr);
220
221    println!(
222        "{}'s team has total health of {}",
223        leader_name, total_health
224    );
225
226    // Can also convert EntityPtr back to BoundEntity's handle
227    let ptr_handle = ptr.handle();
228    let rebound = ptr_handle.bind(&world);
229    assert_eq!(rebound.get::<Name>().unwrap().0, leader_name);
230    println!("Seamless conversion between approaches: OK");
231
232    println!("\nAll assertions passed!");
233}
Source

pub fn get<T: Component>(self, world: &World) -> Option<&T>

Gets a component from the referenced entity.

Returns None if the entity doesn’t exist or doesn’t have the component.

Examples found in repository?
examples/mixed_usage.rs (line 132)
86fn main() {
87    let mut world = World::new();
88
89    println!("=== Mixed Usage Example ===\n");
90
91    // Build a linked list: a -> b -> c -> d
92    println!("Building linked list: a -> b -> c -> d\n");
93
94    let d = world.spawn((Name("d"), LinkedList { next: None })).id();
95    let c = world
96        .spawn((
97            Name("c"),
98            LinkedList {
99                next: Some(EntityHandle::new(d)),
100            },
101        ))
102        .id();
103    let b = world
104        .spawn((
105            Name("b"),
106            LinkedList {
107                next: Some(EntityHandle::new(c)),
108            },
109        ))
110        .id();
111    let a = world
112        .spawn((
113            Name("a"),
114            LinkedList {
115                next: Some(EntityHandle::new(b)),
116            },
117        ))
118        .id();
119
120    // Store handle for later use (EntityHandle is Send + Sync)
121    let a_handle = EntityHandle::new(a);
122
123    // === BoundEntity approach ===
124    println!("--- BoundEntity Approach (explicit &World) ---");
125
126    let bound = a_handle.bind(&world);
127    let length = count_chain_length_bound(bound);
128    println!("Chain length from 'a': {}", length);
129    assert_eq!(length, 4);
130
131    // Get component with explicit world
132    let name = a_handle.get::<Name>(&world).unwrap().0;
133    println!("Starting node name: {}", name);
134
135    // === EntityPtr approach ===
136    println!("\n--- EntityPtr Approach (ergonomic) ---");
137
138    // No unsafe needed! WorldExt provides ergonomic access
139    let ptr = world.entity_ptr(a_handle.entity()); // Convert handle to ptr
140
141    let length = count_chain_length_ptr(ptr);
142    println!("Chain length from 'a': {}", length);
143    assert_eq!(length, 4);
144
145    // Convert back to handle
146    let back_to_handle = ptr.handle();
147    assert_eq!(back_to_handle.entity(), a_handle.entity());
148    println!("Round-trip handle conversion: OK");
149
150    // === Team example ===
151    println!("\n--- Team Example ---");
152
153    // Create team members
154    let alice = world.spawn((Name("Alice"), Health(100))).id();
155    let bob = world.spawn((Name("Bob"), Health(80))).id();
156    let charlie = world.spawn((Name("Charlie"), Health(120))).id();
157
158    // Create team leader with team
159    let leader = world
160        .spawn((
161            Name("Leader"),
162            Health(150),
163            Team(vec![
164                EntityHandle::new(alice),
165                EntityHandle::new(bob),
166                EntityHandle::new(charlie),
167            ]),
168        ))
169        .id();
170
171    // Calculate total team health using EntityPtr
172    let leader_ptr = world.entity_ptr(leader);
173    let total = team_health(leader_ptr);
174    println!("Total team health: {}", total);
175    println!("  Expected: 150 + 100 + 80 + 120 = 450");
176    assert_eq!(total, 450);
177
178    // Find team member using BoundEntity
179    let leader_bound = EntityHandle::new(leader).bind(&world);
180    let bob_bound = find_team_member(leader_bound, "Bob").unwrap();
181    let bob_health = bob_bound.get::<Health>().unwrap().0;
182    println!("Bob's health: {}", bob_health);
183    assert_eq!(bob_health, 80);
184
185    // === Stale Reference Handling ===
186    println!("\n--- Stale Reference Handling ---");
187
188    let temp = world.spawn((Name("Temporary"), Health(50))).id();
189    let temp_handle = EntityHandle::new(temp);
190
191    // Check it's alive
192    println!("Before despawn:");
193    println!("  is_alive: {}", temp_handle.is_alive(&world));
194    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
195    assert!(temp_handle.is_alive(&world));
196
197    // Despawn the entity
198    world.despawn(temp);
199
200    // Handle gracefully returns None
201    println!("After despawn:");
202    println!("  is_alive: {}", temp_handle.is_alive(&world));
203    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
204    assert!(!temp_handle.is_alive(&world));
205    assert!(temp_handle.get::<Name>(&world).is_none());
206
207    // === Mixing approaches in computation ===
208    println!("\n--- Mixing Approaches ---");
209
210    // Start with a stored handle
211    let leader_handle = EntityHandle::new(leader);
212
213    // Use BoundEntity for one part of the computation
214    let bound = leader_handle.bind(&world);
215    let leader_name = bound.get::<Name>().unwrap().0;
216
217    // Switch to EntityPtr for another part
218    let ptr = world.entity_ptr(leader_handle.entity());
219    let total_health = team_health(ptr);
220
221    println!(
222        "{}'s team has total health of {}",
223        leader_name, total_health
224    );
225
226    // Can also convert EntityPtr back to BoundEntity's handle
227    let ptr_handle = ptr.handle();
228    let rebound = ptr_handle.bind(&world);
229    assert_eq!(rebound.get::<Name>().unwrap().0, leader_name);
230    println!("Seamless conversion between approaches: OK");
231
232    println!("\nAll assertions passed!");
233}
Source

pub fn has<T: Component>(self, world: &World) -> bool

Checks if the entity has a component of type T.

Returns false if the entity doesn’t exist.

Source

pub fn is_alive(self, world: &World) -> bool

Checks if the referenced entity is still alive.

Examples found in repository?
examples/mixed_usage.rs (line 193)
86fn main() {
87    let mut world = World::new();
88
89    println!("=== Mixed Usage Example ===\n");
90
91    // Build a linked list: a -> b -> c -> d
92    println!("Building linked list: a -> b -> c -> d\n");
93
94    let d = world.spawn((Name("d"), LinkedList { next: None })).id();
95    let c = world
96        .spawn((
97            Name("c"),
98            LinkedList {
99                next: Some(EntityHandle::new(d)),
100            },
101        ))
102        .id();
103    let b = world
104        .spawn((
105            Name("b"),
106            LinkedList {
107                next: Some(EntityHandle::new(c)),
108            },
109        ))
110        .id();
111    let a = world
112        .spawn((
113            Name("a"),
114            LinkedList {
115                next: Some(EntityHandle::new(b)),
116            },
117        ))
118        .id();
119
120    // Store handle for later use (EntityHandle is Send + Sync)
121    let a_handle = EntityHandle::new(a);
122
123    // === BoundEntity approach ===
124    println!("--- BoundEntity Approach (explicit &World) ---");
125
126    let bound = a_handle.bind(&world);
127    let length = count_chain_length_bound(bound);
128    println!("Chain length from 'a': {}", length);
129    assert_eq!(length, 4);
130
131    // Get component with explicit world
132    let name = a_handle.get::<Name>(&world).unwrap().0;
133    println!("Starting node name: {}", name);
134
135    // === EntityPtr approach ===
136    println!("\n--- EntityPtr Approach (ergonomic) ---");
137
138    // No unsafe needed! WorldExt provides ergonomic access
139    let ptr = world.entity_ptr(a_handle.entity()); // Convert handle to ptr
140
141    let length = count_chain_length_ptr(ptr);
142    println!("Chain length from 'a': {}", length);
143    assert_eq!(length, 4);
144
145    // Convert back to handle
146    let back_to_handle = ptr.handle();
147    assert_eq!(back_to_handle.entity(), a_handle.entity());
148    println!("Round-trip handle conversion: OK");
149
150    // === Team example ===
151    println!("\n--- Team Example ---");
152
153    // Create team members
154    let alice = world.spawn((Name("Alice"), Health(100))).id();
155    let bob = world.spawn((Name("Bob"), Health(80))).id();
156    let charlie = world.spawn((Name("Charlie"), Health(120))).id();
157
158    // Create team leader with team
159    let leader = world
160        .spawn((
161            Name("Leader"),
162            Health(150),
163            Team(vec![
164                EntityHandle::new(alice),
165                EntityHandle::new(bob),
166                EntityHandle::new(charlie),
167            ]),
168        ))
169        .id();
170
171    // Calculate total team health using EntityPtr
172    let leader_ptr = world.entity_ptr(leader);
173    let total = team_health(leader_ptr);
174    println!("Total team health: {}", total);
175    println!("  Expected: 150 + 100 + 80 + 120 = 450");
176    assert_eq!(total, 450);
177
178    // Find team member using BoundEntity
179    let leader_bound = EntityHandle::new(leader).bind(&world);
180    let bob_bound = find_team_member(leader_bound, "Bob").unwrap();
181    let bob_health = bob_bound.get::<Health>().unwrap().0;
182    println!("Bob's health: {}", bob_health);
183    assert_eq!(bob_health, 80);
184
185    // === Stale Reference Handling ===
186    println!("\n--- Stale Reference Handling ---");
187
188    let temp = world.spawn((Name("Temporary"), Health(50))).id();
189    let temp_handle = EntityHandle::new(temp);
190
191    // Check it's alive
192    println!("Before despawn:");
193    println!("  is_alive: {}", temp_handle.is_alive(&world));
194    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
195    assert!(temp_handle.is_alive(&world));
196
197    // Despawn the entity
198    world.despawn(temp);
199
200    // Handle gracefully returns None
201    println!("After despawn:");
202    println!("  is_alive: {}", temp_handle.is_alive(&world));
203    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
204    assert!(!temp_handle.is_alive(&world));
205    assert!(temp_handle.get::<Name>(&world).is_none());
206
207    // === Mixing approaches in computation ===
208    println!("\n--- Mixing Approaches ---");
209
210    // Start with a stored handle
211    let leader_handle = EntityHandle::new(leader);
212
213    // Use BoundEntity for one part of the computation
214    let bound = leader_handle.bind(&world);
215    let leader_name = bound.get::<Name>().unwrap().0;
216
217    // Switch to EntityPtr for another part
218    let ptr = world.entity_ptr(leader_handle.entity());
219    let total_health = team_health(ptr);
220
221    println!(
222        "{}'s team has total health of {}",
223        leader_name, total_health
224    );
225
226    // Can also convert EntityPtr back to BoundEntity's handle
227    let ptr_handle = ptr.handle();
228    let rebound = ptr_handle.bind(&world);
229    assert_eq!(rebound.get::<Name>().unwrap().0, leader_name);
230    println!("Seamless conversion between approaches: OK");
231
232    println!("\nAll assertions passed!");
233}
Source

pub fn bind(self, world: &World) -> BoundEntity<'_>

Binds this handle to a world, creating a BoundEntity for fluent access.

Examples found in repository?
examples/mixed_usage.rs (line 76)
73fn find_team_member<'w>(leader: BoundEntity<'w>, target_name: &str) -> Option<BoundEntity<'w>> {
74    leader.get::<Team>().and_then(|team| {
75        team.0.iter().find_map(|h| {
76            let member = h.bind(leader.world());
77            if member.get::<Name>().map(|n| n.0) == Some(target_name) {
78                Some(member)
79            } else {
80                None
81            }
82        })
83    })
84}
85
86fn main() {
87    let mut world = World::new();
88
89    println!("=== Mixed Usage Example ===\n");
90
91    // Build a linked list: a -> b -> c -> d
92    println!("Building linked list: a -> b -> c -> d\n");
93
94    let d = world.spawn((Name("d"), LinkedList { next: None })).id();
95    let c = world
96        .spawn((
97            Name("c"),
98            LinkedList {
99                next: Some(EntityHandle::new(d)),
100            },
101        ))
102        .id();
103    let b = world
104        .spawn((
105            Name("b"),
106            LinkedList {
107                next: Some(EntityHandle::new(c)),
108            },
109        ))
110        .id();
111    let a = world
112        .spawn((
113            Name("a"),
114            LinkedList {
115                next: Some(EntityHandle::new(b)),
116            },
117        ))
118        .id();
119
120    // Store handle for later use (EntityHandle is Send + Sync)
121    let a_handle = EntityHandle::new(a);
122
123    // === BoundEntity approach ===
124    println!("--- BoundEntity Approach (explicit &World) ---");
125
126    let bound = a_handle.bind(&world);
127    let length = count_chain_length_bound(bound);
128    println!("Chain length from 'a': {}", length);
129    assert_eq!(length, 4);
130
131    // Get component with explicit world
132    let name = a_handle.get::<Name>(&world).unwrap().0;
133    println!("Starting node name: {}", name);
134
135    // === EntityPtr approach ===
136    println!("\n--- EntityPtr Approach (ergonomic) ---");
137
138    // No unsafe needed! WorldExt provides ergonomic access
139    let ptr = world.entity_ptr(a_handle.entity()); // Convert handle to ptr
140
141    let length = count_chain_length_ptr(ptr);
142    println!("Chain length from 'a': {}", length);
143    assert_eq!(length, 4);
144
145    // Convert back to handle
146    let back_to_handle = ptr.handle();
147    assert_eq!(back_to_handle.entity(), a_handle.entity());
148    println!("Round-trip handle conversion: OK");
149
150    // === Team example ===
151    println!("\n--- Team Example ---");
152
153    // Create team members
154    let alice = world.spawn((Name("Alice"), Health(100))).id();
155    let bob = world.spawn((Name("Bob"), Health(80))).id();
156    let charlie = world.spawn((Name("Charlie"), Health(120))).id();
157
158    // Create team leader with team
159    let leader = world
160        .spawn((
161            Name("Leader"),
162            Health(150),
163            Team(vec![
164                EntityHandle::new(alice),
165                EntityHandle::new(bob),
166                EntityHandle::new(charlie),
167            ]),
168        ))
169        .id();
170
171    // Calculate total team health using EntityPtr
172    let leader_ptr = world.entity_ptr(leader);
173    let total = team_health(leader_ptr);
174    println!("Total team health: {}", total);
175    println!("  Expected: 150 + 100 + 80 + 120 = 450");
176    assert_eq!(total, 450);
177
178    // Find team member using BoundEntity
179    let leader_bound = EntityHandle::new(leader).bind(&world);
180    let bob_bound = find_team_member(leader_bound, "Bob").unwrap();
181    let bob_health = bob_bound.get::<Health>().unwrap().0;
182    println!("Bob's health: {}", bob_health);
183    assert_eq!(bob_health, 80);
184
185    // === Stale Reference Handling ===
186    println!("\n--- Stale Reference Handling ---");
187
188    let temp = world.spawn((Name("Temporary"), Health(50))).id();
189    let temp_handle = EntityHandle::new(temp);
190
191    // Check it's alive
192    println!("Before despawn:");
193    println!("  is_alive: {}", temp_handle.is_alive(&world));
194    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
195    assert!(temp_handle.is_alive(&world));
196
197    // Despawn the entity
198    world.despawn(temp);
199
200    // Handle gracefully returns None
201    println!("After despawn:");
202    println!("  is_alive: {}", temp_handle.is_alive(&world));
203    println!("  name: {:?}", temp_handle.get::<Name>(&world).map(|n| n.0));
204    assert!(!temp_handle.is_alive(&world));
205    assert!(temp_handle.get::<Name>(&world).is_none());
206
207    // === Mixing approaches in computation ===
208    println!("\n--- Mixing Approaches ---");
209
210    // Start with a stored handle
211    let leader_handle = EntityHandle::new(leader);
212
213    // Use BoundEntity for one part of the computation
214    let bound = leader_handle.bind(&world);
215    let leader_name = bound.get::<Name>().unwrap().0;
216
217    // Switch to EntityPtr for another part
218    let ptr = world.entity_ptr(leader_handle.entity());
219    let total_health = team_health(ptr);
220
221    println!(
222        "{}'s team has total health of {}",
223        leader_name, total_health
224    );
225
226    // Can also convert EntityPtr back to BoundEntity's handle
227    let ptr_handle = ptr.handle();
228    let rebound = ptr_handle.bind(&world);
229    assert_eq!(rebound.get::<Name>().unwrap().0, leader_name);
230    println!("Seamless conversion between approaches: OK");
231
232    println!("\nAll assertions passed!");
233}

Trait Implementations§

Source§

impl Clone for EntityHandle

Source§

fn clone(&self) -> EntityHandle

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EntityHandle

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<Entity> for EntityHandle

Source§

fn from(entity: Entity) -> Self

Converts to this type from the input type.
Source§

impl From<EntityHandle> for Entity

Source§

fn from(handle: EntityHandle) -> Self

Converts to this type from the input type.
Source§

impl Hash for EntityHandle

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for EntityHandle

Source§

fn eq(&self, other: &EntityHandle) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Copy for EntityHandle

Source§

impl Eq for EntityHandle

Source§

impl Send for EntityHandle

Source§

impl StructuralPartialEq for EntityHandle

Source§

impl Sync for EntityHandle

Auto Trait Implementations§

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DynEq for T
where T: Any + Eq,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

Casts the type to dyn Any.
Source§

fn dyn_eq(&self, other: &(dyn DynEq + 'static)) -> bool

This method tests for self and other values to be equal. Read more
Source§

impl<T> DynHash for T
where T: DynEq + Hash,

Source§

fn as_dyn_eq(&self) -> &(dyn DynEq + 'static)

Casts the type to dyn Any.
Source§

fn dyn_hash(&self, state: &mut dyn Hasher)

Feeds this value into the given Hasher.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.
Source§

impl<T> TypeData for T
where T: 'static + Send + Sync + Clone,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ConditionalSend for T
where T: Send,