Lyndon Alcock
Lyndon Alcock

Reputation: 139

Is there an alternative to this unsafe code for mutable index rust

I am making a chess game and I'm looking to return a mutable null character from an array of pieces when the index of the array (a Vec2 is out of bounds), the reason I need to do this is that my function for moving the piece needs a mutable reference to the Indexed piece, long story short I ended up needing to create a static NULL_PIECE that I could reference within the function but this is potentially quite dangerous as you'll see from my code

impl Index<IVec2> for Board {
    type Output = Piece;
    fn index(&self, index : IVec2) -> &Self::Output{
        if (index.abs() != index) || (index.max_element() > WIDTH-1) {
            &Piece('\0') // this works
        } else {
            let i : usize = (index.x + WIDTH* index.y).try_into().unwrap();
            &self.pieces[i]
        }
    }
}

impl IndexMut<IVec2> for Board {
    fn index_mut(&mut self, index: IVec2) -> &mut Self::Output{
        if (index.abs() != index) || (index.max_element() > WIDTH-1) {
            // &mut Piece('\0')  // this does not work
            unsafe {&mut NULL_PIECE} // this works but I don't like it
        } else {
            let i : usize = (index.x + WIDTH * index.y).try_into().unwrap();
            &mut self.pieces[i]
        }
    }
}

There is a lot of potential for this to cause an error in the event that this mutates to be a piece because of the recursion I've implemented on the piece movement.

You can find the GitHub link here: https://github.com/LyndonAlcock/chess_test/tree/main/src

Upvotes: 1

Views: 117

Answers (1)

cafce25
cafce25

Reputation: 27548

Instead of implementing Index you could write it as:

impl Board {
    fn get(&self, index: IVec2) -> Option<&Piece> {
        if (index.abs() != index) || (index.max_element() > WIDTH-1) {
            None
        } else {
            let i = (index.x + WIDTH* index.y).try_into().ok()?;
            Some(&self.pieces[i])
        }
    }
    fn get_mut(&mut self, index: IVec2) -> Option<&mut Piece> {
        if (index.abs() != index) || (index.max_element() > WIDTH-1) {
            None
        } else {
            let i = (index.x + WIDTH * index.y).try_into().ok()?;
            Some(&mut self.pieces[i])
        }
    }
}

Index implementations should panic when the index is out of bounds.

Upvotes: 5

Related Questions