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. :)
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
Appis running is to create a system that takes&mut World.&mut Worldsystems have exclusive access to the world, which reduces the amount of parallelism that can be achieved.For comparison,
ResourcehasCommands::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
Commandsis becauseCommandhas aSendbound.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 mainCommandsimplementation. This would involve introducing 3 new methods:The exact implementation can be viewed here.
init_non_send_resourceandremove_non_send_resourceare 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_resourceis the only real issue, since it allows the system to construct the non-send resource before inserting it into theWorld.My solution to this was to defer creating the resource until it can be made on the main thread.
insert_non_send_resourcewill take a closure that isSend, but can return a non-send resource. Calling it would look like this:What alternative(s) have you considered?
I believe at least
init_non_send_resourceandremove_non_send_resourceshould be implemented. I can understand ifinsert_non_send_resourcerequires 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
Commandswill make them more on-pace with the universalResource. 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_sendhere. 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 ofCommandsExtto be directly implemented forCommands.I originally came up with this idea while working with integrating
cpalwith Bevy. I was trying to get a microphone working, which required keeping a non-sendStreamtype alive for the course of the app. This would happen duringStartup, but I did not want to claim the entire&mut Worldfor myself.Commandsis a great solution, but lacking in this particular area. :)