use inner::{self as inner_mod};
mod inner {}

// Needed for function consuming vs normal
pub mod marker {
    #[lang = "copy"]
    pub trait Copy {}
}

pub mod ops {
    #[lang = "fn_once"]
    pub trait FnOnce<Args> {}

    #[lang = "fn_mut"]
    pub trait FnMut<Args>: FnOnce<Args> {}

    #[lang = "fn"]
    pub trait Fn<Args>: FnMut<Args> {}
}


struct Foo {
    pub x: i32,
    pub y: i32,
}

trait Bar {
    fn bar(&self) -> i32;
}

impl Bar for Foo {
    fn bar(&self) -> i32 {
        self.x
    }
}

impl Foo {
    fn baz(mut self, f: Foo) -> i32 {
        f.baz(self)
    }

    fn qux(&mut self) {
        self.x = 0;
    }

    fn quop(&self) -> i32 {
        self.x
    }
}

#[derive(Copy)]
struct FooCopy {
    x: u32,
}

impl FooCopy {
    fn baz(self, f: FooCopy) -> u32 {
        f.baz(self)
    }

    fn qux(&mut self) {
        self.x = 0;
    }

    fn quop(&self) -> u32 {
        self.x
    }
}

static mut STATIC_MUT: i32 = 0;

fn foo<'a, T>() -> T {
    foo::<'a, i32>()
}

use ops::Fn;
fn baz<F: Fn() -> ()>(f: F) {
    f()
}

macro_rules! def_fn {
    ($($tt:tt)*) => {$($tt)*}
}

def_fn! {
    fn bar() -> u32 {
        100
    }
}

macro_rules! noop {
    ($expr:expr) => {
        $expr
    }
}

macro_rules! keyword_frag {
    ($type:ty) => ($type)
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        let x = 92;
        vec.push(Foo { x, y: 1 });
    }
    unsafe {
        vec.set_len(0);
        STATIC_MUT = 1;
    }

    for e in vec {
        // Do nothing
    }

    noop!(noop!(1));

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    let Foo { x: z, y } = Foo { x: z, y };

    y;

    let mut foo = Foo { x, y: x };
    let foo2 = Foo { x, y: x };
    foo.quop();
    foo.qux();
    foo.baz(foo2);

    let mut copy = FooCopy { x };
    copy.quop();
    copy.qux();
    copy.baz(copy);

    let a = |x| x;
    let bar = Foo::baz;
}

enum Option<T> {
    Some(T),
    None,
}
use Option::*;

impl<T> Option<T> {
    fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
        match other {
            None => unimplemented!(),
            Nope => Nope,
        }
    }
}