Skip to content

Commit 2a614b8

Browse files
committed
0-sized struct optimization
1 parent b1e8022 commit 2a614b8

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

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

+14-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,18 @@ use crate::world::World;
77
/// [`Commands`] `T` type. Also this only reads the data via `read_unaligned` so unaligned
88
/// accesses are safe.
99
unsafe fn invoke_command<T: Command>(command: *mut u8, world: &mut World) {
10-
let command = command.cast::<T>().read_unaligned();
10+
let command = if std::mem::size_of::<T>() > 0 {
11+
command.cast::<T>().read_unaligned()
12+
} else {
13+
// NOTE: This is necessary because if the `CommandQueueInner` is only filled with 0-sized
14+
// commands the `bytes` vec will never allocate. Then means that `bytes.as_ptr()` could be null
15+
// and reading a null pointer is always UB.
16+
// However according to https://doc.rust-lang.org/std/ptr/index.html
17+
// "The canonical way to obtain a pointer that is valid for zero-sized accesses is NonNull::dangling"
18+
// therefore the below code is safe to do.
19+
let ptr = std::ptr::NonNull::<T>::dangling().as_ptr();
20+
ptr.cast::<T>().read()
21+
};
1122
command.write(world);
1223
}
1324

@@ -43,12 +54,9 @@ impl CommandQueueInner {
4354
func: invoke_command::<C>,
4455
});
4556

46-
// Even if `size` == 0, we still need the vector to allocate.
47-
// When we call `read_unaliged` in `invoke_command`, the ptr must be non-null
48-
// therefore, `self.bytes.as_ptr()` must be non-null.
49-
self.bytes.reserve(size.max(1));
50-
5157
if size > 0 {
58+
self.bytes.reserve(size);
59+
5260
// SAFE: The internal `bytes` vector has enough storage for the
5361
// command (see the call the `reserve` above), and the vector has
5462
// its length set appropriately.

0 commit comments

Comments
 (0)