Ok, this seems a bit silly, but I'm having trouble finding a function to return a statically sized array from the contents of a slice.
The Rust Book sections on arrays and slices says nothing about it. (It does show how to take a slice from an array, but I want to go the other way.) I also checked the documentation for std::slice and std::array, but if it's there, I'm not seeing it.
There is of course the option of writing out each element one by one, but that seems ridiculous. For now, I ended up writing a python one-liner to do it for me.
", ".join(["k[{}]".format(i) for i in range(32)])
So I ended up with this:
use db_key::Key;
#[derive(Clone)]
pub struct Sha256{
bits : [u8;32]
}
impl Key for Sha256 {
fn from_u8(k: &[u8]) -> Self {
Sha256{bits:
// FIXME: This is dumb.
[ k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7], k[8], k[9], k[10], k[11], k[12], k[13], k[14], k[15], k[16], k[17], k[18], k[19], k[20], k[21], k[22], k[23], k[24], k[25], k[26], k[27], k[28], k[29], k[30], k[31] ]
}
}
fn as_slice<T, F: Fn(&[u8]) -> T>(&self, f: F) -> T {
f(&self.bits)
}
}
I'd like to know if there's a proper way, like k.to_array(32) or something along those lines.
And, yes, I realize the above code could fail with out-of-bounds access. I'm not sure what db_key::Key expects on invalid input.
Edit:
Is there a good way to convert a Vec to an array? is similar but less general. A good answer to this will probably also be a good answer to that question with the addition of taking a slice from the vec, which can be done efficiently and concisely. I also don't consider "write a separate conversion function for each size you care about" to be a proper solution.
How to get a slice as a static array in rust? is also similar, but the accepted answer is the hack I had already come up with independently.
You can use a loop to solve it the straightforward (but maybe disappointing) way:
let input = b"abcdef";
let mut array = [0u8; 32];
for (x, y) in input.iter().zip(array.iter_mut()) {
*y = *x;
}
We can use a function to do a runtime size check and turn a slice into a reference to a fixed size array.
Libstd doesn't provide enough traits to reliably check that the input and output types match here, but we could in theory develop that ourselves (for a finite number of array types). Either way, the cast looks like this, U is arbitrary array type you specify.
/// Return a reference to a fixed size array from a slice.
///
/// Return **Some(array)** if the dimensions match, **None** otherwise.
///
/// **Note:** Unsafe because we can't check if the **U** type is really an array.
pub unsafe fn as_array<T, U>(xs: &[T]) -> Option<&U> where
U: AsRef<[T]>,
{
let sz = std::mem::size_of::<U>();
let input_sz = xs.len() * std::mem::size_of::<T>();
// The size check could be relaxed to sz <= input_sz
if sz == input_sz {
Some(&*(xs.as_ptr() as *const U))
} else {
None
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With