@@ -2136,6 +2136,209 @@ impl World {
2136
2136
}
2137
2137
}
2138
2138
2139
+ /// Iterates over all resources in the world.
2140
+ ///
2141
+ /// The returned iterator provides lifetimed, but type-unsafe pointers. Actually reading the contents
2142
+ /// of each resource will require the use of unsafe code.
2143
+ ///
2144
+ /// # Examples
2145
+ ///
2146
+ /// ## Printing the size of all resources
2147
+ ///
2148
+ /// ```
2149
+ /// # use bevy_ecs::prelude::*;
2150
+ /// # #[derive(Resource)]
2151
+ /// # struct A(u32);
2152
+ /// # #[derive(Resource)]
2153
+ /// # struct B(u32);
2154
+ /// #
2155
+ /// # let mut world = World::new();
2156
+ /// # world.insert_resource(A(1));
2157
+ /// # world.insert_resource(B(2));
2158
+ /// let mut total = 0;
2159
+ /// for (info, _) in world.iter_resources() {
2160
+ /// println!("Resource: {}", info.name());
2161
+ /// println!("Size: {} bytes", info.layout().size());
2162
+ /// total += info.layout().size();
2163
+ /// }
2164
+ /// println!("Total size: {} bytes", total);
2165
+ /// # assert_eq!(total, std::mem::size_of::<A>() + std::mem::size_of::<B>());
2166
+ /// ```
2167
+ ///
2168
+ /// ## Dynamically running closures for resources matching specific `TypeId`s
2169
+ ///
2170
+ /// ```
2171
+ /// # use bevy_ecs::prelude::*;
2172
+ /// # use std::collections::HashMap;
2173
+ /// # use std::any::TypeId;
2174
+ /// # use bevy_ptr::Ptr;
2175
+ /// # #[derive(Resource)]
2176
+ /// # struct A(u32);
2177
+ /// # #[derive(Resource)]
2178
+ /// # struct B(u32);
2179
+ /// #
2180
+ /// # let mut world = World::new();
2181
+ /// # world.insert_resource(A(1));
2182
+ /// # world.insert_resource(B(2));
2183
+ /// #
2184
+ /// // In this example, `A` and `B` are resources. We deliberately do not use the
2185
+ /// // `bevy_reflect` crate here to showcase the low-level [`Ptr`] usage. You should
2186
+ /// // probably use something like `ReflectFromPtr` in a real-world scenario.
2187
+ ///
2188
+ /// // Create the hash map that will store the closures for each resource type
2189
+ /// let mut closures: HashMap<TypeId, Box<dyn Fn(&Ptr<'_>)>> = HashMap::new();
2190
+ ///
2191
+ /// // Add closure for `A`
2192
+ /// closures.insert(TypeId::of::<A>(), Box::new(|ptr| {
2193
+ /// // SAFETY: We assert ptr is the same type of A with TypeId of A
2194
+ /// let a = unsafe { &ptr.deref::<A>() };
2195
+ /// # assert_eq!(a.0, 1);
2196
+ /// // ... do something with `a` here
2197
+ /// }));
2198
+ ///
2199
+ /// // Add closure for `B`
2200
+ /// closures.insert(TypeId::of::<B>(), Box::new(|ptr| {
2201
+ /// // SAFETY: We assert ptr is the same type of B with TypeId of B
2202
+ /// let b = unsafe { &ptr.deref::<B>() };
2203
+ /// # assert_eq!(b.0, 2);
2204
+ /// // ... do something with `b` here
2205
+ /// }));
2206
+ ///
2207
+ /// // Iterate all resources, in order to run the closures for each matching resource type
2208
+ /// for (info, ptr) in world.iter_resources() {
2209
+ /// let Some(type_id) = info.type_id() else {
2210
+ /// // It's possible for resources to not have a `TypeId` (e.g. non-Rust resources
2211
+ /// // dynamically inserted via a scripting language) in which case we can't match them.
2212
+ /// continue;
2213
+ /// };
2214
+ ///
2215
+ /// let Some(closure) = closures.get(&type_id) else {
2216
+ /// // No closure for this resource type, skip it.
2217
+ /// continue;
2218
+ /// };
2219
+ ///
2220
+ /// // Run the closure for the resource
2221
+ /// closure(&ptr);
2222
+ /// }
2223
+ /// ```
2224
+ #[ inline]
2225
+ pub fn iter_resources ( & self ) -> impl Iterator < Item = ( & ComponentInfo , Ptr < ' _ > ) > {
2226
+ self . storages
2227
+ . resources
2228
+ . iter ( )
2229
+ . filter_map ( |( component_id, data) | {
2230
+ // SAFETY: If a resource has been initialized, a corresponding ComponentInfo must exist with it's ID.
2231
+ let component_info = unsafe {
2232
+ self . components
2233
+ . get_info ( component_id)
2234
+ . debug_checked_unwrap ( )
2235
+ } ;
2236
+ Some ( ( component_info, data. get_data ( ) ?) )
2237
+ } )
2238
+ }
2239
+
2240
+ /// Mutably iterates over all resources in the world.
2241
+ ///
2242
+ /// The returned iterator provides lifetimed, but type-unsafe pointers. Actually reading from or writing
2243
+ /// to the contents of each resource will require the use of unsafe code.
2244
+ ///
2245
+ /// # Example
2246
+ ///
2247
+ /// ```
2248
+ /// # use bevy_ecs::prelude::*;
2249
+ /// # use bevy_ecs::change_detection::MutUntyped;
2250
+ /// # use std::collections::HashMap;
2251
+ /// # use std::any::TypeId;
2252
+ /// # #[derive(Resource)]
2253
+ /// # struct A(u32);
2254
+ /// # #[derive(Resource)]
2255
+ /// # struct B(u32);
2256
+ /// #
2257
+ /// # let mut world = World::new();
2258
+ /// # world.insert_resource(A(1));
2259
+ /// # world.insert_resource(B(2));
2260
+ /// #
2261
+ /// // In this example, `A` and `B` are resources. We deliberately do not use the
2262
+ /// // `bevy_reflect` crate here to showcase the low-level `MutUntyped` usage. You should
2263
+ /// // probably use something like `ReflectFromPtr` in a real-world scenario.
2264
+ ///
2265
+ /// // Create the hash map that will store the mutator closures for each resource type
2266
+ /// let mut mutators: HashMap<TypeId, Box<dyn Fn(&mut MutUntyped<'_>)>> = HashMap::new();
2267
+ ///
2268
+ /// // Add mutator closure for `A`
2269
+ /// mutators.insert(TypeId::of::<A>(), Box::new(|mut_untyped| {
2270
+ /// // Note: `MutUntyped::as_mut()` automatically marks the resource as changed
2271
+ /// // for ECS change detection, and gives us a `PtrMut` we can use to mutate the resource.
2272
+ /// // SAFETY: We assert ptr is the same type of A with TypeId of A
2273
+ /// let a = unsafe { &mut mut_untyped.as_mut().deref_mut::<A>() };
2274
+ /// # a.0 += 1;
2275
+ /// // ... mutate `a` here
2276
+ /// }));
2277
+ ///
2278
+ /// // Add mutator closure for `B`
2279
+ /// mutators.insert(TypeId::of::<B>(), Box::new(|mut_untyped| {
2280
+ /// // SAFETY: We assert ptr is the same type of B with TypeId of B
2281
+ /// let b = unsafe { &mut mut_untyped.as_mut().deref_mut::<B>() };
2282
+ /// # b.0 += 1;
2283
+ /// // ... mutate `b` here
2284
+ /// }));
2285
+ ///
2286
+ /// // Iterate all resources, in order to run the mutator closures for each matching resource type
2287
+ /// for (info, mut mut_untyped) in world.iter_resources_mut() {
2288
+ /// let Some(type_id) = info.type_id() else {
2289
+ /// // It's possible for resources to not have a `TypeId` (e.g. non-Rust resources
2290
+ /// // dynamically inserted via a scripting language) in which case we can't match them.
2291
+ /// continue;
2292
+ /// };
2293
+ ///
2294
+ /// let Some(mutator) = mutators.get(&type_id) else {
2295
+ /// // No mutator closure for this resource type, skip it.
2296
+ /// continue;
2297
+ /// };
2298
+ ///
2299
+ /// // Run the mutator closure for the resource
2300
+ /// mutator(&mut mut_untyped);
2301
+ /// }
2302
+ /// # assert_eq!(world.resource::<A>().0, 2);
2303
+ /// # assert_eq!(world.resource::<B>().0, 3);
2304
+ /// ```
2305
+ #[ inline]
2306
+ pub fn iter_resources_mut ( & mut self ) -> impl Iterator < Item = ( & ComponentInfo , MutUntyped < ' _ > ) > {
2307
+ self . storages
2308
+ . resources
2309
+ . iter ( )
2310
+ . filter_map ( |( component_id, data) | {
2311
+ // SAFETY: If a resource has been initialized, a corresponding ComponentInfo must exist with it's ID.
2312
+ let component_info = unsafe {
2313
+ self . components
2314
+ . get_info ( component_id)
2315
+ . debug_checked_unwrap ( )
2316
+ } ;
2317
+ let ( ptr, ticks) = data. get_with_ticks ( ) ?;
2318
+
2319
+ // SAFETY:
2320
+ // - We have exclusive access to the world, so no other code can be aliasing the `TickCells`
2321
+ // - We only hold one `TicksMut` at a time, and we let go of it before getting the next one
2322
+ let ticks = unsafe {
2323
+ TicksMut :: from_tick_cells (
2324
+ ticks,
2325
+ self . last_change_tick ( ) ,
2326
+ self . read_change_tick ( ) ,
2327
+ )
2328
+ } ;
2329
+
2330
+ let mut_untyped = MutUntyped {
2331
+ // SAFETY:
2332
+ // - We have exclusive access to the world, so no other code can be aliasing the `Ptr`
2333
+ // - We iterate one resource at a time, and we let go of each `PtrMut` before getting the next one
2334
+ value : unsafe { ptr. assert_unique ( ) } ,
2335
+ ticks,
2336
+ } ;
2337
+
2338
+ Some ( ( component_info, mut_untyped) )
2339
+ } )
2340
+ }
2341
+
2139
2342
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
2140
2343
/// The returned pointer must not be used to modify the resource, and must not be
2141
2344
/// dereferenced after the immutable borrow of the [`World`] ends.
@@ -2554,6 +2757,12 @@ mod tests {
2554
2757
#[ derive( Resource ) ]
2555
2758
struct TestResource ( u32 ) ;
2556
2759
2760
+ #[ derive( Resource ) ]
2761
+ struct TestResource2 ( String ) ;
2762
+
2763
+ #[ derive( Resource ) ]
2764
+ struct TestResource3 ;
2765
+
2557
2766
#[ test]
2558
2767
fn get_resource_by_id ( ) {
2559
2768
let mut world = World :: new ( ) ;
@@ -2594,6 +2803,66 @@ mod tests {
2594
2803
assert_eq ! ( resource. 0 , 43 ) ;
2595
2804
}
2596
2805
2806
+ #[ test]
2807
+ fn iter_resources ( ) {
2808
+ let mut world = World :: new ( ) ;
2809
+ world. insert_resource ( TestResource ( 42 ) ) ;
2810
+ world. insert_resource ( TestResource2 ( "Hello, world!" . to_string ( ) ) ) ;
2811
+ world. insert_resource ( TestResource3 ) ;
2812
+ world. remove_resource :: < TestResource3 > ( ) ;
2813
+
2814
+ let mut iter = world. iter_resources ( ) ;
2815
+
2816
+ let ( info, ptr) = iter. next ( ) . unwrap ( ) ;
2817
+ assert_eq ! ( info. name( ) , std:: any:: type_name:: <TestResource >( ) ) ;
2818
+ // SAFETY: We know that the resource is of type `TestResource`
2819
+ assert_eq ! ( unsafe { ptr. deref:: <TestResource >( ) . 0 } , 42 ) ;
2820
+
2821
+ let ( info, ptr) = iter. next ( ) . unwrap ( ) ;
2822
+ assert_eq ! ( info. name( ) , std:: any:: type_name:: <TestResource2 >( ) ) ;
2823
+ assert_eq ! (
2824
+ // SAFETY: We know that the resource is of type `TestResource2`
2825
+ unsafe { & ptr. deref:: <TestResource2 >( ) . 0 } ,
2826
+ & "Hello, world!" . to_string( )
2827
+ ) ;
2828
+
2829
+ assert ! ( iter. next( ) . is_none( ) ) ;
2830
+ }
2831
+
2832
+ #[ test]
2833
+ fn iter_resources_mut ( ) {
2834
+ let mut world = World :: new ( ) ;
2835
+ world. insert_resource ( TestResource ( 42 ) ) ;
2836
+ world. insert_resource ( TestResource2 ( "Hello, world!" . to_string ( ) ) ) ;
2837
+ world. insert_resource ( TestResource3 ) ;
2838
+ world. remove_resource :: < TestResource3 > ( ) ;
2839
+
2840
+ let mut iter = world. iter_resources_mut ( ) ;
2841
+
2842
+ let ( info, mut mut_untyped) = iter. next ( ) . unwrap ( ) ;
2843
+ assert_eq ! ( info. name( ) , std:: any:: type_name:: <TestResource >( ) ) ;
2844
+ // SAFETY: We know that the resource is of type `TestResource`
2845
+ unsafe {
2846
+ mut_untyped. as_mut ( ) . deref_mut :: < TestResource > ( ) . 0 = 43 ;
2847
+ } ;
2848
+
2849
+ let ( info, mut mut_untyped) = iter. next ( ) . unwrap ( ) ;
2850
+ assert_eq ! ( info. name( ) , std:: any:: type_name:: <TestResource2 >( ) ) ;
2851
+ // SAFETY: We know that the resource is of type `TestResource2`
2852
+ unsafe {
2853
+ mut_untyped. as_mut ( ) . deref_mut :: < TestResource2 > ( ) . 0 = "Hello, world?" . to_string ( ) ;
2854
+ } ;
2855
+
2856
+ assert ! ( iter. next( ) . is_none( ) ) ;
2857
+ std:: mem:: drop ( iter) ;
2858
+
2859
+ assert_eq ! ( world. resource:: <TestResource >( ) . 0 , 43 ) ;
2860
+ assert_eq ! (
2861
+ world. resource:: <TestResource2 >( ) . 0 ,
2862
+ "Hello, world?" . to_string( )
2863
+ ) ;
2864
+ }
2865
+
2597
2866
#[ test]
2598
2867
fn custom_resource_with_layout ( ) {
2599
2868
static DROP_COUNT : AtomicU32 = AtomicU32 :: new ( 0 ) ;
0 commit comments