E0277 when indexing 2D Vec<> in 1D Vec<>

I'm currently trying to make a map generator based off of the articles discussing procedural generation in rust (https://www.jamesbaum.co.uk/blether/procedural-level-generation-rust). I've merged my project code and the code in those articles (mainly at his git hub repository). However, in that article he uses a Vec<Vec<>> to store his tiles, and I'd like to avoid that extra indirection (along with other consequences) as much as possible. To that end I've refactored a lot of his code to work the way I'd like it to work. Right now I have:

#[derive(Clone, Eq, PartialEq)]
pub enum Tile {
    Empty,
    Walkable
}

pub struct Level {
    pub width: usize,
    pub height: usize,
    pub board: Vec<Tile>,
    pub tile_size: usize,
    pub rooms: Vec<Room>,
}

impl std::ops::Index<(usize, usize)> for Level {
    type Output = Tile;

    fn index(&self, (row, col): (usize, usize)) -> &Tile {
        &self.board[self.width*row + col]
    }
}

impl std::ops::IndexMut<(usize, usize)> for Level {
    fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Tile {
        &mut self.board[self.width*row + col]
    }
}

That code defines my main Level type. The rust compiler appears to dislike this majorly:

error[E0277]: the type `[level::Tile]` cannot be indexed by `(usize, usize)`
  --> src\level.rs:48:17
   |
48 |                 self.board[(x, y)] = Tile::Walkable;
   |                 ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `std::slice::SliceIndex<[level::Tile]>` is not implemented for `(usize, usize)`
   = note: required because of the requirements on the impl of `std::ops::Index<(usize, usize)>` for `std::vec::Vec<level::Tile>`

The part its complaining about is this function:

    pub fn add_room(&mut self, room: &Room) {
        for row in 0..room.height {
            for col in 0..room.width {
                let y = room.y + row;
                let x = room.x + col;
                self.board[(x, y)] = Tile::Walkable;
            }
        }
        self.rooms.push(*room);
    }

I'm confused on exactly what the problem is here. I have explicitly indicated that I'd like this index operation to accept a tuple of (usize, usize), and I have enforced that with function parameters. I am quite confused on exactly how this is a problem and how I can fix it.

You implemented Index for Level but in the loop you aren't indexing a Level you're indexing Level.board a Vec<Tile>. Using self[(x, y)] should work.

1 Like