fizyk20/generic-array

Feature request: Conversion from &[[T; N]] to &[GenericArray<T, N>] (and &mut)

Closed this issue · 10 comments

APIs like the cipher crate's BlockEncrypt::encrypt_blocks take a slice of GenericArrays. However, if you're starting with a flat &[u8], it's unergonomic to get to the required type. The unstable slice::as_chunks gives you &[[u8; N]], but going from that to &[GenericArray<u8, _>] seems impossible without a pointer cast or transmute. However, that pointer cast or transmute is valid because GenericArray is repr(transparent), and it would be nice™ if the generic-array crate provided that operation as a safe wrapper.

What would be a good name for these methods? GenericArray::chunks_from_slice/GenericArray::chunks_from_slice_mut?

About to commit them, just having a difficult time naming them.

I was thinking "something similar to whatever the current [T; N] -> GenericArray conversion is called", but that's just From/Into. Which I think could actually be implemented here too, but maybe that's too subtle. To me, chunks_from_slice feels like it's going from a flat list to a chunked one, like slice::as_chunks, but the only thing I can come up with is from_slice_of_arrays and that doesn't carry the implication of producing a slice. 🤷 Yeah, tricky one!

I also wonder if the reverse operation is valuable enough to add at the same time, even if I personally don't have a use for it right now.

This is the signature for what I have so far:

impl<T, N: ArrayLength> GenericArray<T, N> {
    pub const fn chunks_from_slice(slice: &[T]) -> (&[GenericArray<T, N>], &[T])

and the mutable version.

It's worth noting this will be on the 1.0 branch in #138

I can do the opposite with &[GenericArray<T, N>] to &[T]. That would be easy, though determining name and where to place it is not. We can't define methods directly onto &[T] or &[GenericArray<T, N>]. Using traits would invalidate const-usage as well, but might still be a good place to put versions with simpler names.

Oh, I was thinking this signature:

impl <T, N: ArrayLength<T>> GenericArray<T, N> {
  fn from_slice_of_arrays(slice: &[[T; N::USIZE]]) -> &[GenericArray<T, N>] { … }
}

except macro-generated cause N::USIZE isn't actually supported there yet. I guess doing the full jump works too, in which case chunks_from_slice seems like an appropriate name to me.

except macro-generated cause N::USIZE isn't actually supported there yet

That was true in pre-1.0, but as of 1.0 we can do:

pub const fn from_chunks<const U: usize>(chunks: &[[T; U]]) -> &[GenericArray<T, N>]
where
    Const<U>: IntoArrayLength<ArrayLength = N>,
{}

I can include both, and hopefully the full 1.0 releases within a week.

So then there's a naming question for the opposite operation:

pub const fn as_slice_of_arrays<const U: usize>(chunks: &[GenericArray<T, N>]) -> &[[T; U]]
where
    Const<U>: IntoArrayLength<ArrayLength = N>,
{}

Does generic-array have a standard name for the built-in, lang-item fixed-sized arrays?

Does generic-array have a standard name for the built-in, lang-item fixed-sized arrays?

Not really, no.

into_chunks feels somewhat natural as an inverse to from_chunks, but could be confusing to some. "Chunks" being a common term over both &[[T; N]] and &[GenericArray<T, N>] is a tad annoying.

For an inverse of chunks_from_slice, slice_from_chunks works, albeit with the same naming caveats.

At least Rust will prevent them from being used incorrectly.

Also hopefully it won't take years for the Rust crypto crates to upgrade to GA 1.0. If you absolutely must have these backported, I can look into it sometime.

No, it's okay, we're currently just going to use the raw cast like slice::as_chunks. Just trying to make things better for the future!