0

This works, but is very convoluted:

let mut hasher = Sha256::new();
hasher.update(foo);
hasher.update(bar);
let hash = hasher.finalize();
let hash_array: [u8; 16] = hash[0..16].try_into().expect("slice with incorrect length");
let hash128 = u128::from_le_bytes(hash_array);

Is there a way of doing this without:

let hash_array: [u8; 16] = hash[0..16].try_into().expect("slice with incorrect length");

I'm handling a condition which cannot happen, as I know that sha256 produces 32 bytes. How can I tell the compiler that?

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • [This](https://stackoverflow.com/questions/59376378/how-can-i-turn-a-genericarrayt-into-an-array-of-the-same-length/59378107#59378107) and [this](https://stackoverflow.com/questions/48129565/how-to-convert-a-slice-into-an-array-reference) looks very similar to your question. Does it answer your question? – Kitsu Jul 16 '20 at 05:48
  • Does this answer your question? [How can I convert a buffer of a slice of bytes (&\[u8\]) to an integer?](https://stackoverflow.com/questions/29307474/how-can-i-convert-a-buffer-of-a-slice-of-bytes-u8-to-an-integer) – E_net4 Jul 16 '20 at 08:29
  • [`read_u128`](https://docs.rs/byteorder/1.3.4/byteorder/trait.ByteOrder.html#tymethod.read_u128) would let you skip the step of creating the hash array. – E_net4 Jul 16 '20 at 08:30

1 Answers1

2

There is a way but it's a bit convoluted currently: both Rust arrays and GenericArray deref' to slices, so that's what you get when you slice (hash[..16]), which then requires a failible conversion back to an array as the compile-time length information is lost.

However GenericArray<T,N> implements AsRef<[T;N]> and arrays are Copy, so from a GenericArray you can somewhat easily get an array of the same size (by just deref'ing the reference), and thus the question is how to get a GenericArray of the proper size when slices don't work.

Turns out generic_array provides a split. I think I'm missing something to its use because it's a bit gnarly but there you go:

    let hasher = Sha256::new();
    let hash = hasher.finalize();
    let (head, _): (GenericArray<_, U16>, _) = Split::split(hash);
    let hash128 = u128::from_le_bytes(*head.as_ref());

(note: I'm wilfully using the UFCS form of Split::split rather than the method form to limit confusion with slice::split).

Masklinn
  • 34,759
  • 3
  • 38
  • 57