# Enums and Matching Pattern

* **Enums**:
  * Enums (short for "enumerations") are types that allow you to define a value that can be one of several variants.
  * Multiple variants types in single enum:

    ```rust
    enum Message {
      Quit,                       // No data
      Move { x: i32, y: i32 },    // Named fields
      Write(String),              // Single unnamed field
      ChangeColor(u8, u8, u8),    // Multiple unnamed fields
    }
    ```
* **Matching Pattern**:
  * Matching pattern syntax allows you to compare a value against a series of patterns and execute code based on the matching pattern.
  * You can destructure complex data types like structs, enums, and tuples in a `match`.
  * You can add conditions to patterns using `if` guards.
* Reference:
  * [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
  * [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)

## enums1.rs

```rust
#[derive(Debug)]
enum Message {
    // Define a few types of messages as used below.
    Resize,
    Move,
    Echo,
    ChangeColor,
    Quit,
}

fn main() {
    println!("{:?}", Message::Resize);
    println!("{:?}", Message::Move);
    println!("{:?}", Message::Echo);
    println!("{:?}", Message::ChangeColor);
    println!("{:?}", Message::Quit);
}
```

* In this exercise we need to define types of messages as used in the `main` function.
* So we simply add all of the types available in the main function into enum definition.

## enums2.rs

```rust
#[derive(Debug)]
struct Point {
    x: u64,
    y: u64,
}

#[derive(Debug)]
enum Message {
    // Define the different variants used below.
    Resize { width: i32, height: i32 },
    Move(Point),
    Echo(String),
    ChangeColor(i32, i32, i32),
    Quit,
}

impl Message {
    fn call(&self) {
        println!("{self:?}");
    }
}

fn main() {
    let messages = [
        Message::Resize {
            width: 10,
            height: 30,
        },
        Message::Move(Point { x: 10, y: 15 }),
        Message::Echo(String::from("hello world")),
        Message::ChangeColor(200, 255, 255),
        Message::Quit,
    ];

    for message in &messages {
        message.call();
    }
}
```

* We can have multiple variants types in single enum.
* In this task we need to write 5 variants.

  ```rust
  enum Message {
    Resize { width: i32, height: i32 }, // with named field data like a struct
    Move(Point),  // has a struct data 
    Echo(String), // has a single String data
    ChangeColor(i32, i32, i32), // has 3 data like  a tuple
    Quit, // no data
  }
  ```

## enums3.rs

```rust
struct Point {
    x: u64,
    y: u64,
}

enum Message {
    Resize { width: u64, height: u64 },
    Move(Point),
    Echo(String),
    ChangeColor(u8, u8, u8),
    Quit,
}

struct State {
    width: u64,
    height: u64,
    position: Point,
    message: String,
    // RGB color composed of red, green and blue.
    color: (u8, u8, u8),
    quit: bool,
}

impl State {
    fn resize(&mut self, width: u64, height: u64) {
        self.width = width;
        self.height = height;
    }

    fn move_position(&mut self, point: Point) {
        self.position = point;
    }

    fn echo(&mut self, s: String) {
        self.message = s;
    }

    fn change_color(&mut self, red: u8, green: u8, blue: u8) {
        self.color = (red, green, blue);
    }

    fn quit(&mut self) {
        self.quit = true;
    }

    fn process(&mut self, message: Message) {
        // TODO: Create a match expression to process the different message
        // variants using the methods defined above.
        match message {
            Message::Resize {
                width: w,
                height: h,
            } => self.resize(w, h),
            Message::Move(p) => self.move_position(p),
            Message::Echo(s) => self.echo(s),
            Message::ChangeColor(r, g, b) => self.change_color(r, g, b),
            Message::Quit => self.quit(),
        }
    }
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_match_message_call() {
        let mut state = State {
            width: 0,
            height: 0,
            position: Point { x: 0, y: 0 },
            message: String::from("hello world"),
            color: (0, 0, 0),
            quit: false,
        };

        state.process(Message::Resize {
            width: 10,
            height: 30,
        });
        state.process(Message::Move(Point { x: 10, y: 15 }));
        state.process(Message::Echo(String::from("Hello world!")));
        state.process(Message::ChangeColor(255, 0, 255));
        state.process(Message::Quit);

        assert_eq!(state.width, 10);
        assert_eq!(state.height, 30);
        assert_eq!(state.position.x, 10);
        assert_eq!(state.position.y, 15);
        assert_eq!(state.message, "Hello world!");
        assert_eq!(state.color, (255, 0, 255));
        assert!(state.quit);
    }
}
```

* In this exercise we need to create matching pattern syntax for all the available variants in `Message` enum and call it's respective method.
* For each variants that have data, we want to catch or get that data so we can use it as arguments when calling it's respective method.

  ```rust
  match message {
    // bind width -> w and height -> h
    Message::Resize { width: w, height: h } => self.resize(w, h),
    // bind Point -> p
    Message::Move(p) => self.move_position(p),
    // bind String -> s
    Message::Echo(s) => self.echo(s),
    // bind first value -> r
    // bind second value -> r
    // bind third value -> r
    Message::ChangeColor(r, g, b) => self.change_color(r, g, b),
    Message::Quit => self.quit(),
  }
  ```
* This pattern syntax will bind data in the message enum variants into the defined variables.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/rust/rustlings_exercise/08_enums.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
