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
impl EntityHandle
Sourcepub const fn new(entity: Entity) -> Self
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
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}Sourcepub const fn entity(self) -> Entity
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
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}Sourcepub fn get<T: Component>(self, world: &World) -> Option<&T>
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}Sourcepub fn has<T: Component>(self, world: &World) -> bool
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.
Sourcepub fn is_alive(self, world: &World) -> bool
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}Sourcepub fn bind(self, world: &World) -> BoundEntity<'_>
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
impl Clone for EntityHandle
Source§fn clone(&self) -> EntityHandle
fn clone(&self) -> EntityHandle
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for EntityHandle
impl Debug for EntityHandle
Source§impl From<Entity> for EntityHandle
impl From<Entity> for EntityHandle
Source§impl From<EntityHandle> for Entity
impl From<EntityHandle> for Entity
Source§fn from(handle: EntityHandle) -> Self
fn from(handle: EntityHandle) -> Self
Converts to this type from the input type.
Source§impl Hash for EntityHandle
impl Hash for EntityHandle
Source§impl PartialEq for EntityHandle
impl PartialEq for EntityHandle
impl Copy for EntityHandle
impl Eq for EntityHandle
impl Send for EntityHandle
impl StructuralPartialEq for EntityHandle
impl Sync for EntityHandle
Auto Trait Implementations§
impl Freeze for EntityHandle
impl RefUnwindSafe for EntityHandle
impl Unpin for EntityHandle
impl UnwindSafe for EntityHandle
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
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>
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)
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)
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
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
Compare self to
key and return true if they are equal.