I'm currently trying to implement an Array
type that supports element-wise operations, similar to ndarray. This is just a toy project to help me improve my Rust programming skills.
I would like to be able to use this type like so:
let a = arr![1, 2, 3, 4];
let b = arr![8, 7, 6, 5];
assert_eq([9, 9, 9, 9], *(a + b)); // case 1
assert_eq([2, 3, 4, 5], *(a + 1)); // case 2
Currently, I'm able to implement either case 1 or case 2, above, but not both. Here is the relevant code that I've written so far.
use core::{array, ops};
#[macro_export]
macro_rules! arr {
( $($x:expr),* ) => ($crate::Array::from([$($x),*]))
}
#[derive(Debug, Copy, Clone, Hash)]
pub struct Array<T, const N: usize>([T; N]);
// ... some trait impls ...
// Case 1: Implements add (+) operation on `Array<T, N>` with `Array<U, N>` where `T: ops::Add<U>`.
impl<Rhs, T: ops::Add<Rhs>, const N: usize> ops::Add<Array<Rhs, N>> for Array<T, N> {
type Output = Array<<T as ops::Add<Rhs>>::Output, N>;
fn add(self, rhs: Array<Rhs, N>) -> Self::Output {
let mut rhs = rhs.0.into_iter();
// This unwrap will never panic because the arrays are the same length.
Array(self.0.map(|x| x + rhs.next().unwrap()))
}
}
// Case 2: Implements add (+) operation on `Array<T, N>` with `U` where `T: ops::Add<U>`.
impl<Rhs: Copy, T: ops::Add<Rhs>, const N: usize> ops::Add<Rhs> for Array<T, N> {
type Output = Array<<T as ops::Add<Rhs>>::Output, N>;
fn add(self, rhs: Rhs) -> Self::Output {
Array(self.0.map(|x| x + rhs))
}
}
// ... more trait impls ...
But this results in the following compiler error.
error[E0119]: conflicting implementations of trait `Add<Array<_, _>>` for type `Array<_, _>`
--> src/lib.rs:51:1
|
42 | impl<Rhs, T: ops::Add<Rhs>, const N: usize> ops::Add<Array<Rhs, N>> for Array<T, N> {
| ----------------------------------------------------------------------------------- first implementation here
...
51 | impl<Rhs: Copy, T: ops::Add<Rhs>, const N: usize> ops::Add<Rhs> for Array<T, N> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Array<_, _>`
For more information about this error, try `rustc --explain E0119`.
error: could not compile `array` (lib) due to 1 previous error
I understand the reason for the compiler error: The Rhs
generic type parameter could be Array<U, N>
for some U
, so the compiler is unable to tell which implementation to use.
How, though, could I implement this trait to allow operations between Array<T, N>
and any of U
, Array<U, N>
, Array<Array<U, N>>
, etc. for any U
where T: core::ops::Add<U>
?