-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
What problem does this solve or what need does it fill?
The only current way to insert or remove a non-send resource while the App
is running is to create a system that takes &mut World
. &mut World
systems have exclusive access to the world, which reduces the amount of parallelism that can be achieved.
For comparison, Resource
has Commands::insert_resource
, which allows deferring all resource operations to occur at the same time.
I believe the historical reason non-send operations were excluded from Commands
is because Command
has a Send
bound.
What solution would you like?
I recently created a library named bevy_command_non_send
, which adds methods for interacting with non-send resources using commands. I believe it would be useful to others and worth upstreaming into the main Commands
implementation. This would involve introducing 3 new methods:
impl Commands<'_, '_> {
fn init_non_send_resource<R: FromWorld + 'static>(&mut self);
fn insert_non_send_resource<F, R>(&mut self, func: F)
where F: FnOnce() -> R + Send + 'static,
R: 'static;
fn remove_non_send_resource<R: 'static>(&mut self);
}
The exact implementation can be viewed here. init_non_send_resource
and remove_non_send_resource
are simple enough because the system never gains access to the non-send resource, so there are no issues with the data crossing between threads. insert_non_send_resource
is the only real issue, since it allows the system to construct the non-send resource before inserting it into the World
.
My solution to this was to defer creating the resource until it can be made on the main thread. insert_non_send_resource
will take a closure that is Send
, but can return a non-send resource. Calling it would look like this:
struct MyNonSend(*const u8);
fn create_my_non_send(mut commands: Commands) {
commands.insert_non_send_resource(|| {
MyNonSend(std::ptr::null())
});
}
What alternative(s) have you considered?
I believe at least init_non_send_resource
and remove_non_send_resource
should be implemented. I can understand if insert_non_send_resource
requires further consideration, since it is the most complicated of proposed API.
I think non-send resources are a bit of a sore spot right now, but supporting them with Commands
will make them more on-pace with the universal Resource
. I cannot think of any clear alternatives, but feel free to add your thoughts in a comment if I missed anything.
Additional context
For your convenience, I have published the documentation for bevy_command_non_send
here. It comes complete with rigorous documentation and a test suite, which you can view by browsing the source.
Though I say "upstream" in this feature request, I really mean taking heavy inspiration. I don't intend on the functions to be made public in bevy_ecs
, since other commands that are built-in are not as well. Instead, I want the functionality of CommandsExt
to be directly implemented for Commands
.
I originally came up with this idea while working with integrating cpal
with Bevy. I was trying to get a microphone working, which required keeping a non-send Stream
type alive for the course of the app. This would happen during Startup
, but I did not want to claim the entire &mut World
for myself. Commands
is a great solution, but lacking in this particular area. :)