PRO_grammer
PRO_grammer

Reputation: 803

Coupled arrays in Rust

I'm trying to couple 2 arrays to one "parent array". I'd like to have one main array like this for example:

let mut board: [[u8; 4]; 4] = [[1, 6, 5, 2],
                               [4, 8, 9, 3],
                               [9, 2, 2, 5], 
                               [3, 7, 6, 7]];

And 2 other arrays, one for the columns, and one for the 2*2 squares. The two other arrays should update when I change something in the main array.

The two other arrays would look like this in the example:

columns
[[1, 4, 9, 3],
 [6, 8, 2, 7],
 [5, 9, 2, 6],
 [2, 3, 5, 7]]

2*2 squares
[[1, 6, 4, 8],
 [5, 2, 9, 3],
 [9, 2, 3, 7],
 [2, 5, 6, 7]]

now if i say board[0][0] = 5; the columns array should now look like this:

[[5, 4, 9, 3],
 [6, 8, 2, 7],
 [5, 9, 2, 6],
 [2, 3, 5, 7]]

Is there any way to do something like this in Rust?

Upvotes: 1

Views: 69

Answers (1)

Kitsu
Kitsu

Reputation: 3443

Newtype pattern with a related trait implementations might be a solution. These should maps indicies to the base array, e.g. for your first case immutable access can be done via std::ops::Index (playground):

struct Board([[u8; 4]; 4]);

impl Board {
    fn column(&self) -> ColumnBoard {
        ColumnBoard(self)
    }
}

struct ColumnBoard<'a>(&'a Board);

impl<'a> std::ops::Index<(usize, usize)> for ColumnBoard<'a> {
    type Output = u8;
    
    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        &(self.0).0[y][x]
    }
}

fn main() {
    let board = Board([[1, 6, 5, 2],
                       [4, 8, 9, 3],
                       [9, 2, 2, 5], 
                       [3, 7, 6, 7]]);
                       
    let column = board.column();
    assert_eq!(column[(0, 2)], 9);
}

Similarly you can do for the second case. If you want to have an indexing operation twice, you might change Output to temporary structure which also implements std::ops::Index. For mutability, you need additionally implement std::ops::IndexMut (playground):

impl<'a> std::ops::IndexMut<(usize, usize)> for ColumnBoard<'a> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
        &mut (self.0).0[y][x]
    }
}

// besides structures must explicitly declare mutability:

impl Board {
    fn column(&mut self) -> ColumnBoard {
        ColumnBoard(self)
    }
}

struct ColumnBoard<'a>(&'a mut Board);

Upvotes: 2

Related Questions