In this code:
fn unpack_u32(data: &[u8]) -> u32 {
assert_eq!(data.len(), 4);
let res = data[0] as u32 |
(data[1] as u32) << 8 |
(data[2] as u32) << 16 |
(data[3] as u32) << 24;
res
}
fn main() {
let v = vec![0_u8, 1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8];
println!("res: {:X}", unpack_u32(&v[1..5]));
}
the function unpack_u32
accepts only slices of length 4. Is there any way to replace the runtime check assert_eq
with a compile time check?
I think the answer is no as it is; a slice doesn't have a size (or minimum size) as part of the type, so there's nothing for the compiler to check; and similarly a vector is dynamically sized so there's no way to check at compile time that you can take a slice of the right size.
The only way I can see for the information to be even in principle available at compile time is if the function is applied to a compile-time known array. I think you'd still need to implement a procedural macro to do the check (so nightly Rust only, and it's not easy to do).
If the problem is efficiency rather than compile-time checking, you may be able to adjust your code so that, for example, you do one check for
n*4
elements being available beforen
calls to your function; you could use the unsafeget_unchecked
to avoid later redundant bounds checks. Obviously you'd need to be careful to avoid mistakes in the implementation.Yes, kind of. The first step is easy: change the argument type from
&[u8]
to[u8; 4]
:But transforming a slice (like
&v[1..5]
) into an object of type[u8; 4]
is hard. You can of course create such an array simply by specifying all elements, like so:But this is rather ugly to type and doesn't scale well with array size. So the question is "How to get a slice as an array in Rust?". I used a slightly modified version of Matthieu M.'s answer to said question (playground):
As you can see, there is still an
assert
and thus the possibility of runtime failure. The Rust compiler isn't able to know thatv[1..5]
is 4 elements long, because1..5
is just syntactic sugar forRange
which is just a type the compiler knows nothing special about.I had a similar problem, creating a fixed byte-array on stack corresponding to const length of other byte-array (which may change during development time)
A combination of compiler plugin and macro was the solution:
https://github.com/frehberg/rust-sizedbytes