// closures1.rs
//
// "Why do we even need closures?" is a question that gets asked from time to time.
// While it's true that most things that closures can do can also be done with
// regular old structs and enums, closures can make things a lot more clear with a lot
// less clutter compared to structs.
//
// Below is a good example of how one could implement a capturing closure using structs,
// and how closures simplifies this greatly.
//
// Execute `rustlings hint closures1` or use the `hint` watch subcommand for a hint.


trait Doorman {
    fn greet_customer(&self, customer_name: &str);
}

struct GreeterWithState<'a> {
    greeting: &'a str,
}

impl Doorman for GreeterWithState<'_> {
    fn greet_customer(&self, customer_name: &str) {
        println!("{}, {}?", self.greeting, customer_name);
    }
}

fn greet_customers(doorman: impl Doorman) {
    doorman.greet_customer("Bill");
    doorman.greet_customer("Alex");
    doorman.greet_customer("John");
    doorman.greet_customer("Jessie");
}

fn greet_customers_closure(doorman: impl Fn(&str)) {
    doorman("Bill");
    doorman("Alex");
    doorman("John");
    doorman("Jessie");
}

fn main() {
    let greeting = String::from("Hello! How are you");

    // Method 1 for passing in functions with state.
    // Just create a struct, store the state, and add a method.
    // If you need to be generic, it can be a trait method.
    let doorman = GreeterWithState {
        greeting: &greeting,
    };
    greet_customers(doorman);

    // Method 2 for passing in functions with state.
    // Notice that the body of this closure is exactly the same
    // as GreeterWithState's Doorman implementation.
    //
    // This makes things much cleaner with less clutter, but
    // we are forgetting something very important.
    greet_customers_closure(|customer_name| {
        println!("{}, {}?", self.greeting, customer_name); // TODO: Only modify this line
    })
}