1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
//! Helper types to make using the
//! [`generic-array`](https://docs.rs/generic-array/latest/generic_array/) easier.
//!
//! We use the `generic-array` crate, so that we can support situations like:
//! ```text
//! trait Foo {
//! const N: usize;
//! }
//! struct Blarg<F: Foo> {
//! contents: [u8; F::N],
//! }
//! ```
//!
//! While _some_ of the original use cases for `generic-array` can be accomplished since the
//! stabilization of `min_const_generics`, other use cases (like the above) remain unstable (as of
//! Rust 1.65).
//!
//! The `generic_array` crate uses a _type_, instead of a constant, to represent the length of the
//! array. `generic_array` exposes the [`ArrayLength`] trait to denote a type which represents the
//! length of an array. Due to internal reasons, `ArrayLength` is parametrized on the type of an
//! _element_ of the array. For example, we would write code like:
//! ```
//! trait MyBlockCipher {
//! type BlockSize: generic_array::ArrayLength<u8>;
//! }
//! fn foo<C: MyBlockCipher>(x: generic_array::GenericArray<u8, C::BlockSize>) {
//! let _ = x; // do something!
//! }
//! ```
//! This code lets us use `BlockSize` _only_ to create arrays of `u8`s. If you want to create an
//! array of any other size, you're out of luck.
//!
//! In Rust 1.65, Generic Associated Types were stabilized. This provides a solution for us to work
//! around this issue, and let us specify array lengths which can be used with any element type.
//!
//! Use this module as follows:
//! ```
//! # use scuttlebutt::generic_array_length::{AnyArrayLength, Arr};
//! trait MyBlockCipher {
//! type BlockSize: AnyArrayLength;
//! }
//! fn foo<C: MyBlockCipher>(x: Arr<u8, C::BlockSize>) {
//! let _ = x; // do something!
//! }
//! ```
//! Because we've used `AnyArrayLength`, we can instantiate an array of length `BlockSize` with
//! any type that we want! (And we couldn't do that with the "normal" `GenericArray` solution.)
//! ```
//! # use scuttlebutt::generic_array_length::{AnyArrayLength, Arr};
//! # trait MyBlockCipher {
//! # type BlockSize: AnyArrayLength;
//! # }
//! fn blarg<C: MyBlockCipher>(x: Arr<(i32, String), C::BlockSize>) {
//! let _ = x; // do something!
//! }
//! ```
use generic_array::{
typenum::{UInt, UTerm, B0, B1},
ArrayLength, GenericArray,
};
/// A marker type denoting that `Self` corresponds to an `ArrayLength` over any type
pub trait AnyArrayLength {
/// The underlying `ArrayLength`, which should always equal `Self`
type OutputArrayLength<T>: ArrayLength<T>;
}
impl AnyArrayLength for UTerm {
type OutputArrayLength<T> = Self;
}
impl<N: AnyArrayLength> AnyArrayLength for UInt<N, B0> {
type OutputArrayLength<T> = UInt<<N as AnyArrayLength>::OutputArrayLength<T>, B0>;
}
impl<N: AnyArrayLength> AnyArrayLength for UInt<N, B1> {
type OutputArrayLength<T> = UInt<<N as AnyArrayLength>::OutputArrayLength<T>, B1>;
}
/// A [`GenericArray`] of length `N` containing type `T`
///
/// Instead of `N` being constrainted by [`ArrayLength`] (as in `GenericArray`), it's constrainted
/// by [`AnyArrayLength`].
///
/// This type alias resolves to a `GenericArray`, and it can be used with any existing
/// `GenericArray` code.
pub type Arr<T, N> = GenericArray<T, <N as AnyArrayLength>::OutputArrayLength<T>>;