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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use core::ops::{Mul, AddAssign};

use super::*;

//#[const_trait]
pub trait Array2dOps<T, const M: usize, const N: usize>: ArrayOps<[T; N], M>
{
    type Array2d<I, const H: usize, const W: usize>: Array2dOps<I, H, W>;
    
    type Resized2d<const H: usize, const W: usize>: Array2dOps<T, H, W> = Self::Array2d<T, H, W>;
    
    type Transposed: Array2dOps<T, N, M> = Self::Resized2d<N, M>;

    /// Transposes a two-dimensional array (as if it were a matrix)
    /// 
    /// # Example
    /// 
    /// ```rust
    /// use array_trait::*;
    /// 
    /// let matrix: [[u8; 5]; 3] = [
    ///     [1,   2,  3,  4,  5],
    ///     [6,   7,  8,  9, 10],
    ///     [11, 12, 13, 14, 15]
    /// ];
    /// 
    /// assert_eq!(matrix.transpose(), [
    ///     [1,  6, 11],
    ///     [2,  7, 12],
    ///     [3,  8, 13],
    ///     [4,  9, 14],
    ///     [5, 10, 15]
    /// ]);
    /// ```
    fn transpose(self) -> Self::Transposed;
    
    fn mul_matrix<Rhs, const P: usize>(&self, rhs: &Self::Array2d<Rhs, N, P>) -> Self::Array2d<<T as Mul<Rhs>>::Output, M, P>
    where
        T: /*~const*/ Mul<Rhs, Output: /*~const*/ AddAssign + /*~const*/ Default> + Copy,
        Rhs: Copy;
}

impl<T, const M: usize, const N: usize> const Array2dOps<T, M, N> for [[T; N]; M]
{
    type Array2d<I, const H: usize, const W: usize> = [[I; W]; H];
    
    fn transpose(self) -> Self::Transposed
    {
        // Alternative 1: (dirtier)
        let mut this_t: [[T; M]; N] = unsafe {private::uninit()};
        let mut i = 0;
        while i != M
        {
            let mut j = 0;
            while j != N
            {
                unsafe {core::ptr::copy_nonoverlapping(
                    self[i][j].borrow() as *const T,
                    &mut this_t[j][i] as *mut T,
                    1
                )};
                j += 1;
            }
            i += 1;
        }

        core::mem::forget(self);

        this_t

        // Alternative 2: (cleaner)
        /*ArrayOps::fill(const |i| ArrayOps::fill(const |j| unsafe {
            core::ptr::read(&this.borrow()[j][i] as *const T)
        }))*/
    }
    
    fn mul_matrix<Rhs, const P: usize>(&self, rhs: &Self::Array2d<Rhs, N, P>) -> Self::Array2d<<T as Mul<Rhs>>::Output, M, P>
    where
        T: /*~const*/ Mul<Rhs, Output: /*~const*/ AddAssign + /*~const*/ Default> + Copy,
        Rhs: Copy
    {
        let mut prod: [[<T as Mul<Rhs>>::Output; P]; M] = unsafe {private::uninit()};
        let mut m = 0;
        while m != M
        {
            let mut p = 0;
            while p != P
            {
                let mut n = 0;
                while n != N
                {
                    prod[m][p] += self[m][n]*rhs[n][p];
                    n += 1;
                }
                p += 1;
            }
            m += 1;
        }

        prod
    }
}