Search code examples
arraysgenericsrustconst-generics

How to represent an array of only certain sizes in Rust


I would like a data structure that represents an array of values, but which only supports a specific set of sizes and enforces this at compile time. Something like:

struct MyArray<const N: usize>([u8; N]);

But such than N can only be a specific set of values, not just any number representable by usize. For example, I would like a struct can wrap either a [u8; 3], a [u8; 6], or a [u8; 9], but not a [u8; N] for any other N besides 3, 6, and 9. I need the enforcement of this constraint to be at compile time, and ideally part of the type system. Is this possible in Rust? Is there a standard pattern or crate for doing this?


Solution

  • Depending on your use case, you can also represent the custom array as an enum:

    #[derive(Clone, Debug)]
    enum MyArray<T> {
        Three([T; 3]),
        Six([T; 6]),
        Nine([T; 9]),
    }
    
    fn main() {
        let mut array = MyArray::<u8>::Six(Default::default());
    
        if let MyArray::Three(_) = &array {
            println!("Nope.");
        }
    
        if let MyArray::Six(array) = &mut array {
            array
                .iter_mut()
                .enumerate()
                .for_each(|(index, element)| *element = index as u8);
        }
    
        println!("{array:?}");
        println!("Size: {}", std::mem::size_of::<MyArray<u8>>());
    }
    

    Caveat: This will not be as space efficient as the separate impls, due to the nature of enums (size of largest variant). However, if 9 bytes is the maximum size, I assume that this is not an issue in your case.