I've got a trait which is generic over its input and would like to implement it for a type, accepting arrays with arbitrary dimensions.
For example:
pub trait Process<Input> {
type Output;
fn process(&mut self, input: Input) -> Self::Output;
}
type Foo;
impl Process<[f32; 3]> for Foo { ... }
impl Process<[[f64; 128]; 128]> for Foo { ... }
...
Obviously you don't want to write out the infinite number of array impls, so we'll use min const generics.
impl<T; const N: usize> Process<[T; N]> for Foo { ... }
impl<T, const N: usize, const M: usize> Process<[[T; N]; M]> for Foo { ... }
...
However this approach runs into two problems:
- The two impls overlap (the
T
in the first impl could be a[P; N]
) - You still need to copy/paste the impls if you want to work with 3 or more dimensions.
My question is,
how can I write my trait implementation(s) in a way that is generic over the input's dimension?
My first idea was to use specialisation, introducing a helper trait that is implemented on T
as the base case and [T; N]
as the specialisation. This made sense in theory, but ran into overlapping impls when I tried to implement it (playground). I also don't want to rely on unstable features if I can avoid it.
I came up with an alternate form based on declarative macros, but that only works for a finite set of types/dimensions and would be completely unmaintainable (playground). I guess I could pull this out procedural macro but haven't looked that far yet.