# Combining if let statements in Rust

Stack Overflow Asked by Deniz Basgoren on July 24, 2020

I have the following enum, which represents cells in a 2d game world

#[derive(Copy, Clone)]
enum Cell {
Empty,
Soil,
Metal,
Diamond(Falling),
Boulder(Falling),
Player,
Enemy,
Exit
}


where Falling is also an enum:

#[derive(Copy, Clone)]
enum Falling {
True,
False
}


I also have a second enum:

#[derive(Copy, Clone)]
enum PlayerInput {
None,
Up,
Down,
Left,
Right
}


I want to implement the following logic in Rust, according to which a boolean called canMove will be set either true or false:

let cell; // is of type Cell
let input; // is of type PlayerInput

if cell is Player or Metal, FALSE
if cell is Boulder(_) or Diamond(_) and input is Down, FALSE
if cell is Boulder(NotFalling) and input is Up, FALSE
if cell is Boulder(_) and input is Right or Left, and oneMoreCondition(cell,input) is true, FALSE
otherwise TRUE


Now that if let statements don’t support && operators, I’m left with match statements, which will still require nested if let statements, and the resulting code will be less readable. What is the idiomatic way to solve this? Or perhaps I’m misusing enums. Please propose a better solution please

You can use match and match the two variables as a tuple:

#[derive(Copy, Clone)]
enum Cell {
Empty,
Soil,
Metal,
Diamond(Falling),
Boulder(Falling),
Player,
Enemy,
Exit
}

#[derive(Copy, Clone)]
enum Falling {
True,
False
}

#[derive(Copy, Clone)]
enum PlayerInput {
None,
Up,
Down,
Left,
Right
}

fn oneMoreCondition(cell: Cell, input: PlayerInput) -> bool {
// Any arbitrary logic here.
true
}

fn canMove(cell: Cell, input: PlayerInput) -> bool {
match (cell, input) {
(Cell::Player, _) | (Cell::Metal, _) => false,
(Cell::Boulder(_), PlayerInput::Down) | (Cell::Diamond(_), PlayerInput::Down) => false,
(Cell::Boulder(Falling::False), PlayerInput::Up) => false,
(Cell::Boulder(_), PlayerInput::Right) | (Cell::Boulder(_), PlayerInput::Left) if oneMoreCondition(cell, input) => false,
_ => true,
}
}

fn main() {
println!("{}", canMove(Cell::Player, PlayerInput::Left));
println!("{}", canMove(Cell::Boulder(Falling::True), PlayerInput::Down));
println!("{}", canMove(Cell::Boulder(Falling::False), PlayerInput::Up));
println!("{}", canMove(Cell::Boulder(Falling::False), PlayerInput::Right));
println!("{}", canMove(Cell::Enemy, PlayerInput::Left));
}


Output:

false
false
false
false
true


Correct answer by ruohola on July 24, 2020