Reputation: 6083
I have a slice of data and want to create an array reference for a fixed-size subslice:
let slice: &[u8] = &[1, 2, 3, 4, 5];
let array_ref: &[u8; 2] = &slice[..2];
Unfortunately, this doesn't work because the type of &[..2]
is &[u8]
instead of &[u8; 2]
.
I know about <&[u8; 2]>::try_from(slice)
, but that incurs a runtime check where I would prefer to use an API that doesn't do this runtime check since I know at runtime that the size requirement is fulfilled.
Is there any API that allows this?
Upvotes: 2
Views: 1425
Reputation: 10218
In this case, when the slice index is available at compile-time, try_from
will be optimized out. We can check this directly in the playground:
pub fn split_two(slice: &[u8]) -> &[u8; 2] {
slice[..2].try_into().unwrap()
}
Corresponding assembly:
playground::split_two:
cmpq $1, %rsi
jbe .LBB0_1
movq %rdi, %rax
retq
.LBB0_1:
pushq %rax
leaq .L__unnamed_1(%rip), %rdx
movl $2, %edi
callq *core::slice::index::slice_end_index_len_fail@GOTPCREL(%rip)
ud2
.L__unnamed_2:
.ascii "src/lib.rs"
.L__unnamed_1:
.quad .L__unnamed_2
.asciz "\n\000\000\000\000\000\000\000\002\000\000\000\005\000\000"
As you can see, the only check here is the bounds check, i.e. the slice is checked to be at least two elements long; but there's no check for the subslice being two elements long, since that's already guaranteed.
If compiler can see that the slice length is sufficient, the first check would be optimized out too; example:
// "extern" is used as an optimization barrier
extern "Rust" {
fn use_ref(_: &[u8; 2]);
}
pub fn split_two(slice: &[u8; 5]) {
let slice: &[u8] = slice;
// `unsafe` is necessary to call `extern` function (even `extern "Rust"`)
unsafe {
use_ref(slice[..2].try_into().unwrap());
}
}
This is compiled to directly passing the pointer, without any checks at all:
playground::split_two:
jmpq *use_ref@GOTPCREL(%rip)
Upvotes: 6