// Example 1: Hello World, functions, types.

// On with the show!

fn say_hi(x:u8) -> u8 {  /* A function signature */          /*
^  ^     ^      ^  ^                                          *
|  |     |      |  |                                          *
|  |     |      |  ^~ 8-bit `u`nsigned integer                *
|  |     |      |                                             *
|  |     |      ^~~~~~ arrow followed by return type          *
|  |     |                                                    *
|  |     ^~~~~~ parenthesis-delimited argument list           *
|  |                                                          *
|  ^~~~~~ function name                                       *
|                                                             *
^~ `fn` keyword marks start of a function item                *
                                                              *
                                                              */

    println!("Hello world from ex1"); /* a statement */      /*
    ^        ^                      ^~   terminated by `;`    *
    |        |                                                *
    |        ^~~~~~~~~~~~~~~~~~~~~~ string literal in ""      *
    |                                                         *
    ^~~~~~~~ The `println!` macro; all macro invocations      *
             are (currently) marked with a `!` at the end     *
             of their name. Other macros include              *
             `assert!`, `assert_eq!`, `debug!`, `fail!`       *
                                                              */

    return x+1;                                              /*
    ^~~~~~ Ahh; good old `return`                             *
                                                              */
}

fn call_say_hi() -> u8 {

      say_hi(103)                                            /*
      ^~~~~~~~~~~^~~ a call expression...                     *
                 |                                            *
                 ^~ ... but, something's different here ...   *
                                                              *
  ^~~  ... hint: what's "missing" over here                   *
                                                              */
}

fn call_say_hi_twice() -> u8 { say_hi(103); say_hi(103) }
//                Easy to write one-liners: ~~~~~~~~~~^

pub fn main() {
    // There are at least two "interesting" differences between the
    // signatures of `main` and the `say_hi` family above.  Discuss.  :)

    let x : u8 = call_say_hi();                              /*
    ^     ^~~~ a type annotation, just like in fn signatures  *
    |
    ^~~ local variable binding introduced by `let`.           *
                                                              */

    println!("`say_hi` returned {}", x);
    //                          ^    ^~~ a second argument
    //                          |
    //                          ^~~~ a hole for the argument

    let x = call_say_hi_twice();

    println!("Repeat: it returned {}", x);
    //                            ^~ (but unlike printf, Rust has a
    //                                general-purpose default that
    //                                types can also opt into.)

    let c;
    //   ^~ can leave off the initial value for later assignment.
    //
    //      Also letting the type be inferred; Rust allows this for
    //      local variable declarations, but not for `fn` signatures.

    c = x as char;
    //    ^~~~~~~ casting syntax, read like `(char)x` in C/C++/Java.

    println!("x (`{}`) as a char is `{}`", x, c);
}

// EXERCISE: Change all of the above fn's to take and return `u32`
// instead of `u8`.
//
// What happens? Why? How can we address it?