1

I am attempting to create a structure with a few friendly From trait implementations. The structure is a wrapper for an array of arrays of arrays to represent a 3D matrix.

pub struct Table<T, const X: usize, const Y: usize, const Z: usize> {
    pub content: [[[T; X]; Y]; Z],
}

impl<T, const X: usize> From<[T; X]> for Table<T, X, 1, 1> {
    fn from(row: [T; X]) -> Self {
        Table { content: [[row]] }
    }
}

impl<T, const X: usize, const Y: usize> From<[[T; X]; Y]> for Table<T, X, Y, 1> {
    fn from(layer: [[T; X]; Y]) -> Self {
        Table { content: [layer] }
    }
}

impl<T, const X: usize, const Y: usize, const Z: usize> From<[[[T; X]; Y]; Z]>
    for Table<T, X, Y, Z>
{
    fn from(matrix: [[[T; X]; Y]; Z]) -> Self {
        Table { content: matrix }
    }
}

fn main() {
    let i1 = [1];
    let i2 = [[1]];
    let i3 = [[[1]]];

    // Table<i32>
    // notice how you can avoid specifying the constant values
    let tbl1 = Table::from(i1);

    // type annotations needed
    // cannot infer type for struct `Table<_, {_: usize}, {_: usize}, {_: usize}>`
    // let tbl2 = Table::from(i2);
}

I have tried a few alternative solutions including:

  1. to_table trait solution (which lead to the same issue in reverse)
  2. macro_rules (was unable to determine whether the provided types were nested within arrays. I have minimal macro experience)
  3. specific type impl(s) (this works, but is a bad choice because it limits the number of out-of-the-box supported types I could use to populate a table)

I would love to understand how to distinguish generic type implementations from generic type implementations within arrays. I feel that my fundamental issue is that T and [T; _] are the same thing- or rather they confuse the compiler.

Alternative question: Is there a way to specify the non-constant generic types of an element in Rust? I would be happy if using

// possible to skip X, Y, Z?
let tbl: Table<i32> = Table::from([[1]]);

worked, but you have to go through specifying the lengths of all the constants if you manually enter the generic property. Clarification on this second point would be greatly appreciated as well.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Potentially related: [How is there a conflicting implementation of `From` when using a generic type?](https://stackoverflow.com/q/37347311/155423) – Shepmaster Mar 08 '22 at 19:56
  • For your alternative question, I think you can do `Table` – PitaJ Mar 08 '22 at 23:17
  • @Pitaj this does not yield compilable code unfortunately. `type provided when a constant was expected const arguments cannot yet be inferred with _` – Isaac Cloos Mar 09 '22 at 00:38
  • For this particular case, is there any reason why you need the three `From` implementations when you could just have the single `From<[[[T; X]; Y]; Z]>` impl and have the user convert the 1D and 2D arrays to 3D themselves, i.e. `Table::from([[i1]])` and `Table::from([i2])`? – EvilTak Mar 09 '22 at 01:21
  • @EvilTak I would categorize this solution as "just get it done". Along with creating separate functions for each use case. I am hoping to find a single, fluent method that can handle these three requests and potentially more. – Isaac Cloos Mar 09 '22 at 01:57

0 Answers0