Skip to content

Commit bdbf626

Browse files
Implement init_resource for Commands and World (#3079)
# Objective - Fixes #3078 - Fixes #1397 ## Solution - Implement Commands::init_resource. - Also implement for World, for consistency and to simplify internal structure. - While we're here, clean up some of the docs for Command and World resource modification.
1 parent 38f6da5 commit bdbf626

File tree

8 files changed

+219
-144
lines changed

8 files changed

+219
-144
lines changed

crates/bevy_app/src/app.rs

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -647,18 +647,15 @@ impl App {
647647
/// App::new()
648648
/// .insert_resource(MyCounter { counter: 0 });
649649
/// ```
650-
pub fn insert_resource<T>(&mut self, resource: T) -> &mut Self
651-
where
652-
T: Resource,
653-
{
650+
pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
654651
self.world.insert_resource(resource);
655652
self
656653
}
657654

658655
/// Inserts a non-send resource to the app
659656
///
660-
/// You usually want to use `insert_resource`, but there are some special cases when a resource must
661-
/// be non-send.
657+
/// You usually want to use `insert_resource`,
658+
/// but there are some special cases when a resource cannot be sent across threads.
662659
///
663660
/// ## Example
664661
/// ```
@@ -671,19 +668,18 @@ impl App {
671668
/// App::new()
672669
/// .insert_non_send_resource(MyCounter { counter: 0 });
673670
/// ```
674-
pub fn insert_non_send_resource<T>(&mut self, resource: T) -> &mut Self
675-
where
676-
T: 'static,
677-
{
678-
self.world.insert_non_send(resource);
671+
pub fn insert_non_send_resource<R: 'static>(&mut self, resource: R) -> &mut Self {
672+
self.world.insert_non_send_resource(resource);
679673
self
680674
}
681675

682-
/// Initialize a resource in the current [`App`], if it does not exist yet
676+
/// Initialize a resource with standard starting values by adding it to the [`World`]
683677
///
684678
/// If the resource already exists, nothing happens.
685679
///
686-
/// Adds a resource that implements `Default` or [`FromWorld`] trait.
680+
/// The resource must implement the [`FromWorld`] trait.
681+
/// If the `Default` trait is implemented, the `FromWorld` trait will use
682+
/// the `Default::default` method to initialize the resource.
687683
///
688684
/// ## Example
689685
/// ```
@@ -704,32 +700,18 @@ impl App {
704700
/// App::new()
705701
/// .init_resource::<MyCounter>();
706702
/// ```
707-
pub fn init_resource<R>(&mut self) -> &mut Self
708-
where
709-
R: FromWorld + Send + Sync + 'static,
710-
{
711-
// PERF: We could avoid double hashing here, since the `from_resources` call is guaranteed
712-
// not to modify the map. However, we would need to be borrowing resources both
713-
// mutably and immutably, so we would need to be extremely certain this is correct
714-
if !self.world.contains_resource::<R>() {
715-
let resource = R::from_world(&mut self.world);
716-
self.insert_resource(resource);
717-
}
703+
pub fn init_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
704+
self.world.init_resource::<R>();
718705
self
719706
}
720707

721-
/// Initialize a non-send resource in the current [`App`], if it does not exist yet.
708+
/// Initialize a non-send resource with standard starting values by adding it to the [`World`]
722709
///
723-
/// Adds a resource that implements `Default` or [`FromWorld`] trait.
724-
pub fn init_non_send_resource<R>(&mut self) -> &mut Self
725-
where
726-
R: FromWorld + 'static,
727-
{
728-
// See perf comment in init_resource
729-
if self.world.get_non_send_resource::<R>().is_none() {
730-
let resource = R::from_world(&mut self.world);
731-
self.world.insert_non_send(resource);
732-
}
710+
/// The resource must implement the [`FromWorld`] trait.
711+
/// If the `Default` trait is implemented, the `FromWorld` trait will use
712+
/// the `Default::default` method to initialize the resource.
713+
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> &mut Self {
714+
self.world.init_non_send_resource::<R>();
733715
self
734716
}
735717

crates/bevy_ecs/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,8 +1181,8 @@ mod tests {
11811181
#[test]
11821182
fn non_send_resource() {
11831183
let mut world = World::default();
1184-
world.insert_non_send(123i32);
1185-
world.insert_non_send(456i64);
1184+
world.insert_non_send_resource(123i32);
1185+
world.insert_non_send_resource(456i64);
11861186
assert_eq!(*world.get_non_send_resource::<i32>().unwrap(), 123);
11871187
assert_eq!(*world.get_non_send_resource_mut::<i64>().unwrap(), 456);
11881188
}
@@ -1191,7 +1191,7 @@ mod tests {
11911191
#[should_panic]
11921192
fn non_send_resource_panic() {
11931193
let mut world = World::default();
1194-
world.insert_non_send(0i32);
1194+
world.insert_non_send_resource(0i32);
11951195
std::thread::spawn(move || {
11961196
let _ = world.get_non_send_resource_mut::<i32>();
11971197
})

crates/bevy_ecs/src/schedule/executor_parallel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ mod tests {
476476
fn non_send_resource() {
477477
use std::thread;
478478
let mut world = World::new();
479-
world.insert_non_send(thread::current().id());
479+
world.insert_non_send_resource(thread::current().id());
480480
fn non_send(thread_id: NonSend<thread::ThreadId>) {
481481
assert_eq!(thread::current().id(), *thread_id);
482482
}

crates/bevy_ecs/src/system/commands/mod.rs

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
bundle::Bundle,
55
component::Component,
66
entity::{Entities, Entity},
7-
world::World,
7+
world::{FromWorld, World},
88
};
99
use bevy_utils::tracing::{error, warn};
1010
pub use command_queue::CommandQueue;
@@ -261,9 +261,45 @@ impl<'w, 's> Commands<'w, 's> {
261261
self.queue.push(InsertOrSpawnBatch { bundles_iter });
262262
}
263263

264+
/// Inserts a resource with standard starting values to the [`World`].
265+
///
266+
/// If the resource already exists, nothing happens.
267+
///
268+
/// The value given by the [`FromWorld::from_world`] method will be used.
269+
/// Note that any resource with the `Default` trait automatically implements `FromWorld`,
270+
/// and those default values will be here instead.
271+
///
272+
/// See [`World::init_resource`] for more details.
273+
/// Note that commands do not take effect immediately.
274+
/// When possible, prefer the equivalent methods on `App` or `World`.
275+
///
276+
/// # Example
277+
///
278+
/// ```
279+
/// # use bevy_ecs::prelude::*;
280+
/// #
281+
/// # #[derive(Default)]
282+
/// # struct Scoreboard {
283+
/// # current_score: u32,
284+
/// # high_score: u32,
285+
/// # }
286+
/// #
287+
/// # fn system(mut commands: Commands) {
288+
/// commands.init_resource::<Scoreboard>();
289+
/// # }
290+
/// # system.system();
291+
/// ```
292+
pub fn init_resource<R: Resource + FromWorld>(&mut self) {
293+
self.queue.push(InitResource::<R> {
294+
_phantom: PhantomData::<R>::default(),
295+
})
296+
}
297+
264298
/// Inserts a resource to the [`World`], overwriting any previous value of the same type.
265299
///
266300
/// See [`World::insert_resource`] for more details.
301+
/// Note that commands do not take effect immediately.
302+
/// When possible, prefer the equivalent methods on `App` or `World`.
267303
///
268304
/// # Example
269305
///
@@ -283,7 +319,7 @@ impl<'w, 's> Commands<'w, 's> {
283319
/// # }
284320
/// # bevy_ecs::system::assert_is_system(system);
285321
/// ```
286-
pub fn insert_resource<T: Resource>(&mut self, resource: T) {
322+
pub fn insert_resource<R: Resource>(&mut self, resource: R) {
287323
self.queue.push(InsertResource { resource })
288324
}
289325

@@ -306,8 +342,8 @@ impl<'w, 's> Commands<'w, 's> {
306342
/// # }
307343
/// # bevy_ecs::system::assert_is_system(system);
308344
/// ```
309-
pub fn remove_resource<T: Resource>(&mut self) {
310-
self.queue.push(RemoveResource::<T> {
345+
pub fn remove_resource<R: Resource>(&mut self) {
346+
self.queue.push(RemoveResource::<R> {
311347
phantom: PhantomData,
312348
});
313349
}
@@ -713,23 +749,33 @@ where
713749
}
714750
}
715751

716-
pub struct InsertResource<T: Resource> {
717-
pub resource: T,
752+
pub struct InitResource<R: Resource + FromWorld> {
753+
_phantom: PhantomData<R>,
718754
}
719755

720-
impl<T: Resource> Command for InsertResource<T> {
756+
impl<R: Resource + FromWorld> Command for InitResource<R> {
757+
fn write(self, world: &mut World) {
758+
world.init_resource::<R>();
759+
}
760+
}
761+
762+
pub struct InsertResource<R: Resource> {
763+
pub resource: R,
764+
}
765+
766+
impl<R: Resource> Command for InsertResource<R> {
721767
fn write(self, world: &mut World) {
722768
world.insert_resource(self.resource);
723769
}
724770
}
725771

726-
pub struct RemoveResource<T: Resource> {
727-
pub phantom: PhantomData<T>,
772+
pub struct RemoveResource<R: Resource> {
773+
pub phantom: PhantomData<R>,
728774
}
729775

730-
impl<T: Resource> Command for RemoveResource<T> {
776+
impl<R: Resource> Command for RemoveResource<R> {
731777
fn write(self, world: &mut World) {
732-
world.remove_resource::<T>();
778+
world.remove_resource::<R>();
733779
}
734780
}
735781

crates/bevy_ecs/src/system/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ mod tests {
422422
world.insert_resource(false);
423423
struct NotSend1(std::rc::Rc<i32>);
424424
struct NotSend2(std::rc::Rc<i32>);
425-
world.insert_non_send(NotSend1(std::rc::Rc::new(0)));
425+
world.insert_non_send_resource(NotSend1(std::rc::Rc::new(0)));
426426

427427
fn sys(
428428
op: Option<NonSend<NotSend1>>,
@@ -446,8 +446,8 @@ mod tests {
446446
struct NotSend1(std::rc::Rc<i32>);
447447
struct NotSend2(std::rc::Rc<i32>);
448448

449-
world.insert_non_send(NotSend1(std::rc::Rc::new(1)));
450-
world.insert_non_send(NotSend2(std::rc::Rc::new(2)));
449+
world.insert_non_send_resource(NotSend1(std::rc::Rc::new(1)));
450+
world.insert_non_send_resource(NotSend2(std::rc::Rc::new(2)));
451451

452452
fn sys(_op: NonSend<NotSend1>, mut _op2: NonSendMut<NotSend2>, mut run: ResMut<bool>) {
453453
*run = true;

0 commit comments

Comments
 (0)