<commit_before>extern crate discord;
extern crate serde_json;

use std::fs::File;
use std::io::Read;
use discord::{Discord, State};
use discord::model::{Event, ChannelId};

fn main() {
    // Read and set config vars
    let mut file = File::open("config.json").unwrap();
    let mut config = String::new();
    file.read_to_string(&mut config).unwrap();

    let json: serde_json::Value = serde_json::from_str(&config).unwrap();
    let bot_tokens = json.find_path(&["bot-token"]).unwrap();
    let welcome_message = json.find_path(&["welcome-message"]).unwrap();

    println!("bot-token has been set to {} from config", bot_tokens);
    println!("welcome-message has been set to {} from the config",
             welcome_message);

    // Login to the API
    let discord = Discord::from_bot_token(bot_tokens.as_string().unwrap()).expect("Login Fail");

    // establish websocket and voice connection
    let (mut connection, ready) = discord.connect().expect("connect failed");
    println!("[Ready] {} is serving {} servers",
             ready.user.username,
             ready.servers.len());
    let mut state = State::new(ready);

    // receive events forever
    loop {
        let event = match connection.recv_event() {
            Ok(event) => event,
            Err(err) => {
                println!("[Warning] Receive error: {:?}", err);
                if let discord::Error::WebSocket(..) = err {
                    // Handle the websocket connection being dropped
                    let (new_connection, ready) = discord.connect().expect("connect failed");
                    connection = new_connection;
                    state = State::new(ready);
                    println!("[Ready] Reconnected successfully.");
                }
                if let discord::Error::Closed(..) = err {
                    break;
                }
                continue;
            }
        };
        state.update(&event);

        match event {
            Event::MessageCreate(message) => {
                use std::ascii::AsciiExt;
                // safeguard: stop if the message is from us
                if message.author.id == state.user().id {
                    continue;
                }

                // reply to a command if there was one
                let mut split = message.content.split(" ");
                let first_word = split.next().unwrap_or("");
                let argument = split.next().unwrap_or("");

                if first_word.eq_ignore_ascii_case("!dj") {
                    let vchan = state.find_voice_user(message.author.id);
                    if argument.eq_ignore_ascii_case("stop") {
                        vchan.map(|(sid, _)| connection.voice(sid).stop());
                    } else if argument.eq_ignore_ascii_case("quit") {
                        vchan.map(|(sid, _)| connection.drop_voice(sid));
                    } else {
                        let output = if let Some((server_id, channel_id)) = vchan {
                            match discord::voice::open_ytdl_stream(&argument) {
                                Ok(stream) => {
                                    let voice = connection.voice(server_id);
                                    voice.set_deaf(true);
                                    voice.connect(channel_id);
                                    voice.play(stream);
                                    String::new()
                                }
                                Err(error) => format!("Error: {}", error),
                            }
                        } else {
                            "You must be in a voice channel to DJ".to_owned()
                        };
                        if output.len() > 0 {
                            warn(discord.send_message(&message.channel_id, &output, "", false));
                        }
                    }
                }
            }
            Event::VoiceStateUpdate(server_id, _) => {
                // If someone moves/hangs up, and we are in a voice channel,
                if let Some(cur_channel) = connection.voice(server_id).current_channel() {
                    // and our current voice channel is empty, disconnect from voice
                    if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
                        if srv.voice_states
                            .iter()
                            .filter(|vs| vs.channel_id == Some(cur_channel))
                            .count() <= 1 {
                            connection.voice(server_id).disconnect();
                        }
                    }
                }
            }

            Event::ServerMemberAdd(server_joined_id, member) => {
                let channel_id = ChannelId(server_joined_id.0);

                for server in state.servers() {
                    if server.id == server_joined_id {
                        discord.send_message(&channel_id,
                                             &format!("Welcome {} to {}! {}",
                                                      member.user.name,
                                                      server.name,
                                                      welcome_message),
                                             "",
                                             false);

                        break;
                    }
                }
            }
            _ => {} // discard other events
        }
    }
}

fn warn<T, E: ::std::fmt::Debug>(result: Result<T, E>) {
    match result {
        Ok(_) => {}
        Err(err) => println!("[Warning] {:?}", err),
    }
}
<commit_msg>Handle message limiting error for New User Welcome Bot<commit_after>extern crate discord;
extern crate serde_json;

use std::fs::File;
use std::io::Read;
use discord::{Discord, State};
use discord::model::{Event, ChannelId};

fn main() {
    // Read and set config vars
    let mut file = File::open("config.json").unwrap();
    let mut config = String::new();
    file.read_to_string(&mut config).unwrap();

    let json: serde_json::Value = serde_json::from_str(&config).unwrap();
    let bot_tokens = json.find_path(&["bot-token"]).unwrap();
    let welcome_message = json.find_path(&["welcome-message"]).unwrap();

    println!("bot-token has been set to {} from config", bot_tokens);
    println!("welcome-message has been set to {} from the config",
             welcome_message);

    // Login to the API
    let discord = Discord::from_bot_token(bot_tokens.as_string().unwrap()).expect("Login Fail");

    // establish websocket and voice connection
    let (mut connection, ready) = discord.connect().expect("connect failed");
    println!("[Ready] {} is serving {} servers",
             ready.user.username,
             ready.servers.len());
    let mut state = State::new(ready);

    // receive events forever
    loop {
        let event = match connection.recv_event() {
            Ok(event) => event,
            Err(err) => {
                println!("[Warning] Receive error: {:?}", err);
                if let discord::Error::WebSocket(..) = err {
                    // Handle the websocket connection being dropped
                    let (new_connection, ready) = discord.connect().expect("connect failed");
                    connection = new_connection;
                    state = State::new(ready);
                    println!("[Ready] Reconnected successfully.");
                }
                if let discord::Error::Closed(..) = err {
                    break;
                }
                continue;
            }
        };
        state.update(&event);

        match event {
            Event::MessageCreate(message) => {
                use std::ascii::AsciiExt;
                // safeguard: stop if the message is from us
                if message.author.id == state.user().id {
                    continue;
                }

                // reply to a command if there was one
                let mut split = message.content.split(" ");
                let first_word = split.next().unwrap_or("");
                let argument = split.next().unwrap_or("");

                if first_word.eq_ignore_ascii_case("!dj") {
                    let vchan = state.find_voice_user(message.author.id);
                    if argument.eq_ignore_ascii_case("stop") {
                        vchan.map(|(sid, _)| connection.voice(sid).stop());
                    } else if argument.eq_ignore_ascii_case("quit") {
                        vchan.map(|(sid, _)| connection.drop_voice(sid));
                    } else {
                        let output = if let Some((server_id, channel_id)) = vchan {
                            match discord::voice::open_ytdl_stream(&argument) {
                                Ok(stream) => {
                                    let voice = connection.voice(server_id);
                                    voice.set_deaf(true);
                                    voice.connect(channel_id);
                                    voice.play(stream);
                                    String::new()
                                }
                                Err(error) => format!("Error: {}", error),
                            }
                        } else {
                            "You must be in a voice channel to DJ".to_owned()
                        };
                        if output.len() > 0 {
                            warn(discord.send_message(&message.channel_id, &output, "", false));
                        }
                    }
                }
            }
            Event::VoiceStateUpdate(server_id, _) => {
                // If someone moves/hangs up, and we are in a voice channel,
                if let Some(cur_channel) = connection.voice(server_id).current_channel() {
                    // and our current voice channel is empty, disconnect from voice
                    if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
                        if srv.voice_states
                            .iter()
                            .filter(|vs| vs.channel_id == Some(cur_channel))
                            .count() <= 1 {
                            connection.voice(server_id).disconnect();
                        }
                    }
                }
            }
            Event::ServerMemberAdd(server_joined_id, member) => {
                let channel_id = ChannelId(server_joined_id.0);

                for server in state.servers() {
                    if server.id == server_joined_id {
                        let result = discord.send_message(&channel_id,
                                                          &format!("Welcome {} to {}! {}",
                                                                   member.user.name,
                                                                   server.name,
                                                                   welcome_message),
                                                          "",
                                                          false);

                        match result {
                            Ok(_) => {} // nothing to do, it was sent - the `Ok()` contains a `Message` if you want it
                            Err(discord::Error::RateLimited(milliseconds)) => {
                                let sleep_duration = std::time::Duration::from_millis(milliseconds);
                                std::thread::sleep(sleep_duration);
                                let _ = discord.send_message(&channel_id,
                                                             &format!("Welcome {} to {}! {}",
                                                                      member.user.name,
                                                                      server.name,
                                                                      welcome_message),
                                                             "",
                                                             false);
                            }
                            _ => {} // discard all other events
                        }
                        break;
                    }
                }
            }
            _ => {} // discard other events
        }
    }
}

fn warn<T, E: ::std::fmt::Debug>(result: Result<T, E>) {
    match result {
        Ok(_) => {}
        Err(err) => println!("[Warning] {:?}", err),
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate posix_mq;
extern crate libc;
extern crate nix;

use clap::{App, SubCommand, Arg, ArgMatches, AppSettings};
use posix_mq::{Name, Queue, Message};
use std::fs::{read_dir, File};
use std::io::{self, Read, Write};
use std::process::exit;

fn run_ls() {
    let mqueues = read_dir("/dev/mqueue")
        .expect("Could not read message queues");

    for queue in mqueues {
        let path = queue.unwrap().path();
        let status = {
            let mut file = File::open(&path)
                .expect("Could not open queue file");

            let mut content = String::new();
            file.read_to_string(&mut content).expect("Could not read queue file");

            content
        };

        let queue_name = path.components().last().unwrap().as_os_str();
        println!("{:?}: {}", queue_name, status)
    };
}

fn run_inspect(queue_name: &str) {
    let name = Name::new(queue_name).expect("Invalid queue name");
    let queue = Queue::open(name).expect("Could not open queue");

    println!("Queue {}:\n", queue_name);
    println!("Max. message size: {} bytes", queue.max_size());
    println!("Max. # of pending messages: {}", queue.max_pending());
}

fn run_create(cmd: &ArgMatches) {
    if let Some(rlimit) = cmd.value_of("rlimit") {
        set_rlimit(rlimit.parse().expect("Invalid rlimit value"));
    }

    let name = Name::new(cmd.value_of("queue").unwrap())
        .expect("Invalid queue name");

    let max_pending: i64 = cmd.value_of("max-pending").unwrap().parse().unwrap();
    let max_size: i64 = cmd.value_of("max-size").unwrap().parse().unwrap();

    let queue = Queue::create(name, max_pending, max_size * 1024);

    match queue {
        Ok(_)  => println!("Queue created successfully"),
        Err(e) => {
            writeln!(io::stderr(), "Could not create queue: {}", e).ok();
            exit(1);
        },
    };
}

fn run_receive(queue_name: &str) {
    let name = Name::new(queue_name).expect("Invalid queue name");
    let queue = Queue::open(name).expect("Could not open queue");

    let message = match queue.receive() {
        Ok(msg) => msg,
        Err(e) => {
            writeln!(io::stderr(), "Failed to receive message: {}", e).ok();
            exit(1);
        }
    };

    // Attempt to write the message out as a string, but write out raw bytes if it turns out to not
    // be UTF-8 encoded data.
    match String::from_utf8(message.data.clone()) {
        Ok(string) => println!("{}", string),
        Err(_) => {
            writeln!(io::stderr(), "Message not UTF-8 encoded!").ok();
            io::stdout().write(message.data.as_ref()).ok();
        }
    };
}

fn run_send(queue_name: &str, content: &str) {
    let name = Name::new(queue_name).expect("Invalid queue name");
    let queue = Queue::open(name).expect("Could not open queue");

    let message = Message {
        data: content.as_bytes().to_vec(),
        priority: 0,
    };

    match queue.send(&message) {
        Ok(_) => (),
        Err(e) => {
            writeln!(io::stderr(), "Could not send message: {}", e).ok();
            exit(1);
        }
    }
}

fn run_rlimit() {
    let mut rlimit = libc::rlimit {
        rlim_cur: 0,
        rlim_max: 0,
    };

    let mut errno = 0;
    unsafe {
        let res = libc::getrlimit(libc::RLIMIT_MSGQUEUE, &mut rlimit);
        if res != 0 {
            errno = nix::errno::errno();
        }
    };

    if errno != 0 {
        writeln!(io::stderr(), "Could not get message queue rlimit: {}", errno).ok();
    } else {
        println!("Message queue rlimit:");
        println!("Current limit: {}", rlimit.rlim_cur);
        println!("Maximum limit: {}", rlimit.rlim_max);
    }
}

fn set_rlimit(new_limit: u64) {
    let rlimit = libc::rlimit {
        rlim_cur: new_limit,
        rlim_max: new_limit,
    };

    let mut errno: i32 = 0;
    unsafe {
        let res = libc::setrlimit(libc::RLIMIT_MSGQUEUE, &rlimit);
        if res != 0 {
            errno = nix::errno::errno();
        }
    }

    match errno {
        0 => println!("Set RLIMIT_MSGQUEUE hard limit to {}", new_limit),
        _ => {
            // Not mapping these error codes to messages for now, the user can
            // look up the meaning in setrlimit(2).
            panic!("Could not set hard limit: {}", errno);
        }
    };
}

fn main() {
    let ls = SubCommand::with_name("ls").about("list message queues");

    let queue_arg = Arg::with_name("queue").required(true).takes_value(true);

    let rlimit_arg = Arg::with_name("rlimit")
        .help("RLIMIT_MSGQUEUE to set for this command")
        .long("rlimit")
        .takes_value(true);

    let inspect = SubCommand::with_name("inspect")
        .about("inspect details about a queue")
        .arg(&queue_arg);

    let create = SubCommand::with_name("create")
        .about("Create a new queue")
        .arg(&queue_arg)
        .arg(&rlimit_arg)
        .arg(Arg::with_name("max-size")
            .help("maximum message size (in kB)")
            .long("max-size")
            .required(true)
            .takes_value(true))
        .arg(Arg::with_name("max-pending")
            .help("maximum # of pending messages")
            .long("max-pending")
            .required(true)
            .takes_value(true));

    let receive = SubCommand::with_name("receive")
        .about("Receive a message from a queue")
        .arg(&queue_arg);

    let send = SubCommand::with_name("send")
        .about("Send a message to a queue")
        .arg(&queue_arg)
        .arg(Arg::with_name("message")
            .help("the message to send")
            .required(true));

    let rlimit = SubCommand::with_name("rlimit")
        .about("Get the message queue rlimit")
        .setting(AppSettings::SubcommandRequiredElseHelp);

    let matches = App::new("mq")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .version("0.0.1")
        .about("Administrate and inspect POSIX message queues")
        .subcommand(ls)
        .subcommand(inspect)
        .subcommand(create)
        .subcommand(receive)
        .subcommand(send)
        .subcommand(rlimit)
        .get_matches();

    match matches.subcommand() {
        ("ls", _) => run_ls(),
        ("inspect", Some(cmd)) => run_inspect(cmd.value_of("queue").unwrap()),
        ("create",  Some(cmd)) => run_create(cmd),
        ("receive", Some(cmd)) => run_receive(cmd.value_of("queue").unwrap()),
        ("send",    Some(cmd)) => run_send(
            cmd.value_of("queue").unwrap(),
            cmd.value_of("message").unwrap()
        ),
        ("rlimit",  _) => run_rlimit(),
        _ => unimplemented!(),
    }
}
<commit_msg>fix(main): Fix formatting of queue name in ls-output<commit_after>extern crate clap;
extern crate posix_mq;
extern crate libc;
extern crate nix;

use clap::{App, SubCommand, Arg, ArgMatches, AppSettings};
use posix_mq::{Name, Queue, Message};
use std::fs::{read_dir, File};
use std::io::{self, Read, Write};
use std::process::exit;

fn run_ls() {
    let mqueues = read_dir("/dev/mqueue")
        .expect("Could not read message queues");

    for queue in mqueues {
        let path = queue.unwrap().path();
        let status = {
            let mut file = File::open(&path)
                .expect("Could not open queue file");

            let mut content = String::new();
            file.read_to_string(&mut content).expect("Could not read queue file");

            content
        };

        let queue_name = path.components().last().unwrap()
            .as_os_str()
            .to_string_lossy();

        println!("/{}: {}", queue_name, status)
    };
}

fn run_inspect(queue_name: &str) {
    let name = Name::new(queue_name).expect("Invalid queue name");
    let queue = Queue::open(name).expect("Could not open queue");

    println!("Queue {}:\n", queue_name);
    println!("Max. message size: {} bytes", queue.max_size());
    println!("Max. # of pending messages: {}", queue.max_pending());
}

fn run_create(cmd: &ArgMatches) {
    if let Some(rlimit) = cmd.value_of("rlimit") {
        set_rlimit(rlimit.parse().expect("Invalid rlimit value"));
    }

    let name = Name::new(cmd.value_of("queue").unwrap())
        .expect("Invalid queue name");

    let max_pending: i64 = cmd.value_of("max-pending").unwrap().parse().unwrap();
    let max_size: i64 = cmd.value_of("max-size").unwrap().parse().unwrap();

    let queue = Queue::create(name, max_pending, max_size * 1024);

    match queue {
        Ok(_)  => println!("Queue created successfully"),
        Err(e) => {
            writeln!(io::stderr(), "Could not create queue: {}", e).ok();
            exit(1);
        },
    };
}

fn run_receive(queue_name: &str) {
    let name = Name::new(queue_name).expect("Invalid queue name");
    let queue = Queue::open(name).expect("Could not open queue");

    let message = match queue.receive() {
        Ok(msg) => msg,
        Err(e) => {
            writeln!(io::stderr(), "Failed to receive message: {}", e).ok();
            exit(1);
        }
    };

    // Attempt to write the message out as a string, but write out raw bytes if it turns out to not
    // be UTF-8 encoded data.
    match String::from_utf8(message.data.clone()) {
        Ok(string) => println!("{}", string),
        Err(_) => {
            writeln!(io::stderr(), "Message not UTF-8 encoded!").ok();
            io::stdout().write(message.data.as_ref()).ok();
        }
    };
}

fn run_send(queue_name: &str, content: &str) {
    let name = Name::new(queue_name).expect("Invalid queue name");
    let queue = Queue::open(name).expect("Could not open queue");

    let message = Message {
        data: content.as_bytes().to_vec(),
        priority: 0,
    };

    match queue.send(&message) {
        Ok(_) => (),
        Err(e) => {
            writeln!(io::stderr(), "Could not send message: {}", e).ok();
            exit(1);
        }
    }
}

fn run_rlimit() {
    let mut rlimit = libc::rlimit {
        rlim_cur: 0,
        rlim_max: 0,
    };

    let mut errno = 0;
    unsafe {
        let res = libc::getrlimit(libc::RLIMIT_MSGQUEUE, &mut rlimit);
        if res != 0 {
            errno = nix::errno::errno();
        }
    };

    if errno != 0 {
        writeln!(io::stderr(), "Could not get message queue rlimit: {}", errno).ok();
    } else {
        println!("Message queue rlimit:");
        println!("Current limit: {}", rlimit.rlim_cur);
        println!("Maximum limit: {}", rlimit.rlim_max);
    }
}

fn set_rlimit(new_limit: u64) {
    let rlimit = libc::rlimit {
        rlim_cur: new_limit,
        rlim_max: new_limit,
    };

    let mut errno: i32 = 0;
    unsafe {
        let res = libc::setrlimit(libc::RLIMIT_MSGQUEUE, &rlimit);
        if res != 0 {
            errno = nix::errno::errno();
        }
    }

    match errno {
        0 => println!("Set RLIMIT_MSGQUEUE hard limit to {}", new_limit),
        _ => {
            // Not mapping these error codes to messages for now, the user can
            // look up the meaning in setrlimit(2).
            panic!("Could not set hard limit: {}", errno);
        }
    };
}

fn main() {
    let ls = SubCommand::with_name("ls").about("list message queues");

    let queue_arg = Arg::with_name("queue").required(true).takes_value(true);

    let rlimit_arg = Arg::with_name("rlimit")
        .help("RLIMIT_MSGQUEUE to set for this command")
        .long("rlimit")
        .takes_value(true);

    let inspect = SubCommand::with_name("inspect")
        .about("inspect details about a queue")
        .arg(&queue_arg);

    let create = SubCommand::with_name("create")
        .about("Create a new queue")
        .arg(&queue_arg)
        .arg(&rlimit_arg)
        .arg(Arg::with_name("max-size")
            .help("maximum message size (in kB)")
            .long("max-size")
            .required(true)
            .takes_value(true))
        .arg(Arg::with_name("max-pending")
            .help("maximum # of pending messages")
            .long("max-pending")
            .required(true)
            .takes_value(true));

    let receive = SubCommand::with_name("receive")
        .about("Receive a message from a queue")
        .arg(&queue_arg);

    let send = SubCommand::with_name("send")
        .about("Send a message to a queue")
        .arg(&queue_arg)
        .arg(Arg::with_name("message")
            .help("the message to send")
            .required(true));

    let rlimit = SubCommand::with_name("rlimit")
        .about("Get the message queue rlimit")
        .setting(AppSettings::SubcommandRequiredElseHelp);

    let matches = App::new("mq")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .version("1.0.0")
        .about("Administrate and inspect POSIX message queues")
        .subcommand(ls)
        .subcommand(inspect)
        .subcommand(create)
        .subcommand(receive)
        .subcommand(send)
        .subcommand(rlimit)
        .get_matches();

    match matches.subcommand() {
        ("ls", _) => run_ls(),
        ("inspect", Some(cmd)) => run_inspect(cmd.value_of("queue").unwrap()),
        ("create",  Some(cmd)) => run_create(cmd),
        ("receive", Some(cmd)) => run_receive(cmd.value_of("queue").unwrap()),
        ("send",    Some(cmd)) => run_send(
            cmd.value_of("queue").unwrap(),
            cmd.value_of("message").unwrap()
        ),
        ("rlimit",  _) => run_rlimit(),
        _ => unimplemented!(),
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: main.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      Entry point.
*/

extern mod std;
extern mod opengles;
extern mod glfw;

#[path = "gl/mod.rs"]
mod gl;

#[path = "math/mod.rs"]
mod math;

#[macro_escape]
#[path = "gl/check.rs"]
mod check;

#[path = "obj/bsp/map.rs"]
mod map;

#[path = "gl/ttf/mod.rs"]
mod ttf;

#[path = "obj/primitive/sphere.rs"]
mod sphere;

fn main() {
  glfw::set_error_callback(error_callback);

  do glfw::spawn {
    glfw::window_hint::context_version(3, 3);
    glfw::window_hint::opengl_profile(glfw::OPENGL_CORE_PROFILE);
    glfw::window_hint::opengl_forward_compat(true);

    let window = @glfw::Window::create(1024, 768, "Q^3", glfw::Windowed).unwrap();
    window.make_context_current();

    let camera = @mut gl::Camera::new(window);
    camera.init();

    /* Setup callbacks. */
    window.set_cursor_mode(glfw::CURSOR_CAPTURED);
    do window.set_size_callback |_, width, height|
    { camera.resize(width as i32, height as i32); }
    do window.set_cursor_pos_callback |_, x, y|
    { camera.mouse_moved(x, y); }
    do window.set_key_callback |window, key, action|
    {
      camera.key_action(key, action);
      key_callback(window, key, action);
    }

    let mut sphere = sphere::Sphere::new(100.0, 5);

    /* Temp test for font loading. */
    let mut font_renderer = ttf::Renderer::new();
    let mut font = ttf::Font::new("data/test.ttf", 50);

    let map = map::Map::new("data/q3ctf1.bsp");
    //let map = map::Map::new("data/dk.bsp");

    /* Shader Creation. */
    let shader = @mut gl::Shader_Builder::new_with_files("data/shaders/color.vert", "data/shaders/color.frag");
    shader.bind();

    let proj_loc = shader.get_uniform_location(~"proj");
    let world_loc = shader.get_uniform_location(~"world");

    let mut cur_time = (std::time::precise_time_ns() / 10000) as f32; // Hundredth of a second
    let mut last_time = cur_time;

    while !window.should_close() {
      glfw::poll_events();

      /* Delta time. */
      let delta = cur_time - last_time;
      last_time = cur_time;
      cur_time = (std::time::precise_time_ns() / 10000) as f32;

      camera.update(delta);
      shader.bind();
      shader.update_uniform_mat(proj_loc, camera.projection);
      shader.update_uniform_mat(world_loc, camera.view);

      let fps = camera.frame_rate;

      check!(gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT));
      {
        //map.draw();
        sphere.draw();
        font_renderer.begin(camera);
        font_renderer.render(fmt!("%?", fps), math::Vec2f::new(0.0, 0.0), &font);
        font_renderer.end();
      } window.swap_buffers();

      std::timer::sleep(@std::uv::global_loop::get(), 1000 / (camera.target_frame_rate as uint));
    }
  }
}

fn key_callback(window: &glfw::Window, key: libc::c_int, action: libc::c_int)
{
  if action == glfw::PRESS && key == glfw::KEY_ESCAPE
  { window.set_should_close(true); }
}

fn error_callback(error: libc::c_int, description: ~str)
{ error!("GLFW Error %?: %s", error, description); }

<commit_msg> #7 Showing the map for master<commit_after>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: main.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      Entry point.
*/

extern mod std;
extern mod opengles;
extern mod glfw;

#[path = "gl/mod.rs"]
mod gl;

#[path = "math/mod.rs"]
mod math;

#[macro_escape]
#[path = "gl/check.rs"]
mod check;

#[path = "obj/bsp/map.rs"]
mod map;

#[path = "gl/ttf/mod.rs"]
mod ttf;

#[path = "obj/primitive/sphere.rs"]
mod sphere;

fn main() {
  glfw::set_error_callback(error_callback);

  do glfw::spawn {
    glfw::window_hint::context_version(3, 3);
    glfw::window_hint::opengl_profile(glfw::OPENGL_CORE_PROFILE);
    glfw::window_hint::opengl_forward_compat(true);

    let window = @glfw::Window::create(1024, 768, "Q^3", glfw::Windowed).unwrap();
    window.make_context_current();

    let camera = @mut gl::Camera::new(window);
    camera.init();

    /* Setup callbacks. */
    window.set_cursor_mode(glfw::CURSOR_CAPTURED);
    do window.set_size_callback |_, width, height|
    { camera.resize(width as i32, height as i32); }
    do window.set_cursor_pos_callback |_, x, y|
    { camera.mouse_moved(x, y); }
    do window.set_key_callback |window, key, action|
    {
      camera.key_action(key, action);
      key_callback(window, key, action);
    }

    let mut sphere = sphere::Sphere::new(100.0, 5);

    /* Temp test for font loading. */
    let mut font_renderer = ttf::Renderer::new();
    let mut font = ttf::Font::new("data/test.ttf", 50);

    let map = map::Map::new("data/q3ctf1.bsp");
    //let map = map::Map::new("data/dk.bsp");

    /* Shader Creation. */
    let shader = @mut gl::Shader_Builder::new_with_files("data/shaders/color.vert", "data/shaders/color.frag");
    shader.bind();

    let proj_loc = shader.get_uniform_location(~"proj");
    let world_loc = shader.get_uniform_location(~"world");

    let mut cur_time = (std::time::precise_time_ns() / 10000) as f32; // Hundredth of a second
    let mut last_time = cur_time;

    while !window.should_close() {
      glfw::poll_events();

      /* Delta time. */
      let delta = cur_time - last_time;
      last_time = cur_time;
      cur_time = (std::time::precise_time_ns() / 10000) as f32;

      camera.update(delta);
      shader.bind();
      shader.update_uniform_mat(proj_loc, camera.projection);
      shader.update_uniform_mat(world_loc, camera.view);

      let fps = camera.frame_rate;

      check!(gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT));
      {
        map.draw();
        //sphere.draw();
        font_renderer.begin(camera);
        font_renderer.render(fmt!("%?", fps), math::Vec2f::new(0.0, 0.0), &font);
        font_renderer.end();
      } window.swap_buffers();

      std::timer::sleep(@std::uv::global_loop::get(), 1000 / (camera.target_frame_rate as uint));
    }
  }
}

fn key_callback(window: &glfw::Window, key: libc::c_int, action: libc::c_int)
{
  if action == glfw::PRESS && key == glfw::KEY_ESCAPE
  { window.set_should_close(true); }
}

fn error_callback(error: libc::c_int, description: ~str)
{ error!("GLFW Error %?: %s", error, description); }

<|endoftext|>


<commit_before>#![deny(
    unused_allocation,
    unused_attributes,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_parens,
    unused_results,
    unused_unsafe,
    unused_variables,

    dead_code,
    deprecated
)]

extern crate term;
extern crate git2;
extern crate prompt_buffer;

use prompt_buffer::thread::PromptThread;
use prompt_buffer::buffer::PromptBuffer;

use std::collections::HashMap;
use std::old_io::{
    Acceptor,
    Command,
    File,
    fs,
    Listener,
    process,
    stdio,
    timer,
};
use std::old_io::fs::PathExtensions;
use std::old_io::net::pipe::{
    UnixListener,
    UnixStream,
};
use std::env;
use std::time::Duration;
use std::error::Error;

mod git;
mod due_date;

fn get_prompt() -> PromptBuffer {
    let mut buf = PromptBuffer::new();
    buf.add_plugin(due_date::DueDatePlugin::new());
    buf.add_plugin(git::GitPlugin::new());

    buf
}

fn exe_changed() -> u64 {
    match env::current_exe() {
        Ok(exe_path) => {
            match exe_path.stat() {
                Ok(s) => s.modified,
                _ => 0u64
            }
        },
        Err(_) => 0u64
    }
}

fn current_pid(pid_path: &Path) -> Result<i32, Box<Error>> {
    let mut file = try!(File::open(pid_path));
    let contents = try!(file.read_to_string());
    Ok(try!(contents.parse()))
}

macro_rules! sock_try {
    ($x:expr) => {
        match $x {
            Ok(v) => v,
            Err(_) => continue
        }
    };
}

#[allow(dead_code)]
enum RunMode {
    Daemon,
    Main,
    Test
}

#[allow(dead_code)]
fn main() {
    let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
    run(match args.len() {
        2 => RunMode::Daemon,
        1 => RunMode::Main,
        _ => panic!("Number of arguments must be 0 or 1")
    });
}

fn do_daemon(socket_path: &Path) {
    let stdout_path = Path::new("/var/log/megaprompt/current.out");
    let stderr_path = Path::new("/var/log/megaprompt/current.err");

    let _ = stdio::set_stdout(Box::new(File::create(&stdout_path)));
    let _ = stdio::set_stderr(Box::new(File::create(&stderr_path)));

    let last_modified = exe_changed();
    let mut threads: HashMap<Path, PromptThread> = HashMap::new();

    if socket_path.exists() {
        fs::unlink(socket_path).unwrap();
    }

    let stream = match UnixListener::bind(socket_path) {
        Err(_) => panic!("Failed to bind to socket"),
        Ok(stream) => stream
    };

    for mut connection in stream.listen().incoming() {
        let c = &mut connection;

        let output = Path::new(sock_try!(c.read_to_string()));
        println!("Preparing to respond to for {}", output.display());

        let keys: Vec<Path> = threads.keys().map(|x| { x.clone() }).collect();
        for path in keys.iter() {
            if !threads.get_mut(path).unwrap().is_alive() {
                println!("- Remove thread {}", path.display());
                let _ = threads.remove(path);
            }
        }

        if !threads.contains_key(&output) {
            println!("+ Add thread {}", output.display());
            let _ = threads.insert(output.clone(), PromptThread::new(output.clone(), &get_prompt));
        }

        for path in threads.keys() {
            println!("* Active thread {}", path.display());
        }

        let mut thr = threads.get_mut(&output).unwrap();

        sock_try!(write!(c, "{}", thr.get(&get_prompt)));

        println!("");

        if last_modified != exe_changed() {
            sock_try!(write!(c, "♻  "));
            return;
        }
    }
}

fn do_main(socket_path: &Path) {
    let pid_path = Path::new("/var/log/megaprompt/current.pid");

    let current_pid = current_pid(&pid_path).ok().unwrap_or(-1);

    match process::Process::kill(current_pid, 0) {
        Err(_) => {
            // We need to start up the daemon again
            let child = Command::new(env::args().next().unwrap().into_string().unwrap().as_slice())
                .arg("daemon")
                .detached().spawn().unwrap();

            let mut f = match File::create(&pid_path) {
                Ok(f) => f,
                Err(_) => panic!("Unable to open pid file")
            };

            write!(&mut f, "{}", child.id()).unwrap();

            println!("Spawned child {}", child.id());

            child.forget();

            timer::sleep(Duration::milliseconds(10));
        }
        _ => {}
    }

    let mut stream = match UnixStream::connect(socket_path) {
        Err(_) => {
            println!("Can't connect");
            get_prompt().print();
            return;
        },
        Ok(stream) => stream
    };

    write!(&mut stream, "{}", env::current_dir().unwrap().display()).unwrap();
    stream.close_write().unwrap();
    stream.set_read_timeout(Some(200));
    match stream.read_to_string() {
        Ok(s) => println!("{}", s),
        Err(_) => {
            println!("Response too slow");
            get_prompt().print_fast();
            return;
        }
    }
}

fn run(mode: RunMode) {
    let socket_path = Path::new("/tmp/megaprompt-socket");

    match mode {
        RunMode::Daemon => do_daemon(&socket_path),
        RunMode::Main => do_main(&socket_path),
        RunMode::Test => {}
    }
}

#[test]
fn test_main_does_not_error() {
    run(RunMode::Test);
}
<commit_msg>Actually fix for rustc 1.0.0-nightly (b63cee4a1 2015-02-14 17:01:11 +0000)<commit_after>#![deny(
    unused_allocation,
    unused_attributes,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_parens,
    unused_results,
    unused_unsafe,
    unused_variables,

    dead_code,
    deprecated
)]

extern crate term;
extern crate git2;
extern crate prompt_buffer;

use prompt_buffer::thread::PromptThread;
use prompt_buffer::buffer::PromptBuffer;

use std::collections::HashMap;
use std::old_io::{
    Acceptor,
    Command,
    File,
    fs,
    Listener,
    process,
    stdio,
    timer,
};
use std::old_io::fs::PathExtensions;
use std::old_io::net::pipe::{
    UnixListener,
    UnixStream,
};
use std::env;
use std::time::Duration;
use std::error::Error;

mod git;
mod due_date;

fn get_prompt() -> PromptBuffer {
    let mut buf = PromptBuffer::new();
    buf.add_plugin(due_date::DueDatePlugin::new());
    buf.add_plugin(git::GitPlugin::new());

    buf
}

fn exe_changed() -> u64 {
    match env::current_exe() {
        Ok(exe_path) => {
            match exe_path.stat() {
                Ok(s) => s.modified,
                _ => 0u64
            }
        },
        Err(_) => 0u64
    }
}

fn current_pid(pid_path: &Path) -> Result<i32, Box<Error>> {
    let mut file = try!(File::open(pid_path));
    let contents = try!(file.read_to_string());
    Ok(try!(contents.parse()))
}

macro_rules! sock_try {
    ($x:expr) => {
        match $x {
            Ok(v) => v,
            Err(_) => continue
        }
    };
}

#[allow(dead_code)]
enum RunMode {
    Daemon,
    Main,
    Test
}

#[allow(dead_code)]
fn main() {
    let args: Vec<String> = env::args().collect();
    run(match args.len() {
        2 => RunMode::Daemon,
        1 => RunMode::Main,
        _ => panic!("Number of arguments must be 0 or 1")
    });
}

fn do_daemon(socket_path: &Path) {
    let stdout_path = Path::new("/var/log/megaprompt/current.out");
    let stderr_path = Path::new("/var/log/megaprompt/current.err");

    let _ = stdio::set_stdout(Box::new(File::create(&stdout_path)));
    let _ = stdio::set_stderr(Box::new(File::create(&stderr_path)));

    let last_modified = exe_changed();
    let mut threads: HashMap<Path, PromptThread> = HashMap::new();

    if socket_path.exists() {
        fs::unlink(socket_path).unwrap();
    }

    let stream = match UnixListener::bind(socket_path) {
        Err(_) => panic!("Failed to bind to socket"),
        Ok(stream) => stream
    };

    for mut connection in stream.listen().incoming() {
        let c = &mut connection;

        let output = Path::new(sock_try!(c.read_to_string()));
        println!("Preparing to respond to for {}", output.display());

        let keys: Vec<Path> = threads.keys().map(|x| { x.clone() }).collect();
        for path in keys.iter() {
            if !threads.get_mut(path).unwrap().is_alive() {
                println!("- Remove thread {}", path.display());
                let _ = threads.remove(path);
            }
        }

        if !threads.contains_key(&output) {
            println!("+ Add thread {}", output.display());
            let _ = threads.insert(output.clone(), PromptThread::new(output.clone(), &get_prompt));
        }

        for path in threads.keys() {
            println!("* Active thread {}", path.display());
        }

        let mut thr = threads.get_mut(&output).unwrap();

        sock_try!(write!(c, "{}", thr.get(&get_prompt)));

        println!("");

        if last_modified != exe_changed() {
            sock_try!(write!(c, "♻  "));
            return;
        }
    }
}

fn do_main(socket_path: &Path) {
    let pid_path = Path::new("/var/log/megaprompt/current.pid");

    let current_pid = current_pid(&pid_path).ok().unwrap_or(-1);

    match process::Process::kill(current_pid, 0) {
        Err(_) => {
            // We need to start up the daemon again
            let child = Command::new(env::args().next().unwrap().as_slice())
                .arg("daemon")
                .detached().spawn().unwrap();

            let mut f = match File::create(&pid_path) {
                Ok(f) => f,
                Err(_) => panic!("Unable to open pid file")
            };

            write!(&mut f, "{}", child.id()).unwrap();

            println!("Spawned child {}", child.id());

            child.forget();

            timer::sleep(Duration::milliseconds(10));
        }
        _ => {}
    }

    let mut stream = match UnixStream::connect(socket_path) {
        Err(_) => {
            println!("Can't connect");
            get_prompt().print();
            return;
        },
        Ok(stream) => stream
    };

    write!(&mut stream, "{}", env::current_dir().unwrap().display()).unwrap();
    stream.close_write().unwrap();
    stream.set_read_timeout(Some(200));
    match stream.read_to_string() {
        Ok(s) => println!("{}", s),
        Err(_) => {
            println!("Response too slow");
            get_prompt().print_fast();
            return;
        }
    }
}

fn run(mode: RunMode) {
    let socket_path = Path::new("/tmp/megaprompt-socket");

    match mode {
        RunMode::Daemon => do_daemon(&socket_path),
        RunMode::Main => do_main(&socket_path),
        RunMode::Test => {}
    }
}

#[test]
fn test_main_does_not_error() {
    run(RunMode::Test);
}
<|endoftext|>


<commit_before>mod buf;
mod checkers;
mod format;
mod lexer;
mod nodes;
mod parser;
#[cfg(test)]
mod rename;
mod translator;
use md5;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::env;
use std::fs;
use std::io::BufRead;
use std::path::Path;
use std::process::{exit, Command, Stdio};
use std::str;
use std::string::String;

#[test]
fn test_rename() {
    let mut m = parser::get_module(&"json".to_string(), &String::from(".")).unwrap();
    let exports = checkers::get_exports(&m);
    let mut names: Vec<String> = Vec::new();
    for e in exports.consts {
        names.push(e.id);
    }
    for f in exports.fns {
        names.push(f.form.name);
    }
    for t in exports.types {
        names.push(t.form.alias);
    }
    println!("{:?}", names);
    rename::rename_mod(&mut m, &"kek".to_string(), &names);
    let c = translator::translate(&m);
    fs::write("out.c", format::format_compat_module(&c)).unwrap();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args[1] == "build" {
        match build(&args[2..]) {
            Ok(_) => exit(0),
            Err(m) => {
                eprintln!("{}", m);
                exit(1);
            }
        }
    }
    if args[1] == "deptree" {
        exit(deptree(&args[2..]));
    }
    if args[1] == "exports" {
        exit(exports(&args[2..]));
    }
    if args[1] == "test" {
        match run_tests(&args[2..]) {
            Err(s) => {
                eprintln!("{}", s);
                exit(1);
            }
            Ok(_) => {
                exit(0);
            }
        }
    }
    exit(1);
}

fn find_tests(dirpath: &String) -> Result<Vec<String>, String> {
    let mut paths: Vec<String> = Vec::new();
    for entry_result in fs::read_dir(dirpath).unwrap() {
        let result = entry_result.unwrap();
        let path = result.path();
        if path.to_str().unwrap().ends_with(".test.c") {
            paths.push(String::from(path.to_str().unwrap()));
        } else if path.is_dir() {
            paths.append(&mut find_tests(&String::from(path.to_str().unwrap())).unwrap())
        }
    }
    return Ok(paths);
}

fn run_tests(args: &[String]) -> Result<(), String> {
    let mut fails = 0;
    let mut total = 0;
    for arg in args {
        let tests = find_tests(arg)?;
        for path in tests {
            build_prog(&path, &String::from("test.out")).unwrap();
            let output = Command::new("./test.out").output().unwrap();
            let errstr = str::from_utf8(&output.stderr).unwrap();
            let outstr = str::from_utf8(&output.stdout).unwrap().trim_end();
            let mark = if output.status.success() {
                "OK"
            } else {
                "FAIL "
            };
            if !output.status.success() {
                fails += 1;
            }
            if outstr != "" {
                println!("{} {}: {}", mark, path, outstr);
            } else {
                println!("{} {}", mark, path);
            }
            if errstr != "" {
                println!("stderr:\n{}", errstr);
            }
            total += 1
        }
        println!("{} tests", total)
    }
    if fails > 1 {
        return Err(format!("{} tests failed", fails));
    }
    if fails == 1 {
        return Err(format!("1 test failed"));
    }
    return Ok(());
}

fn get_first_module(path: &String) -> Result<nodes::Module, String> {
    let name = String::from(Path::new(path).file_name().unwrap().to_str().unwrap());
    return parser::get_module(&name, &path);
}

#[test]
fn snapshots() {
    for entry in fs::read_dir("test/snapshots").unwrap() {
        let tmp = entry.unwrap().path();
        let path = tmp.to_str().unwrap();
        if path.ends_with(".out.c") {
            continue;
        }
        println!("{}", path);

        // get the output
        let m = get_first_module(&path.to_string()).unwrap();
        let mods = resolve_deps(&m);
        let c_mods: Vec<nodes::CompatModule> =
            mods.iter().map(|m| translator::translate(&m)).collect();
        let result = format::format_compat_module(&c_mods[0]);

        let snapshot_path = path.replace(".c", ".out.c");
        if env::var("UPDATE_SNAPSHOT").is_ok() {
            fs::write(snapshot_path, result).unwrap();
        } else {
            assert_eq!(result, fs::read_to_string(snapshot_path).unwrap());
        }
    }
}

fn build_prog(source_path: &String, output_name: &String) -> Result<(), String> {
    // Get the module we're building.
    let main_module = get_first_module(source_path)?;

    // Get all modules that our module depends on. This includes our module as
    // well, so this is a complete list of modules required for the build.
    let all_modules = resolve_deps(&main_module);

    // Dome some checks.
    for m in &all_modules {
        for imp in module_imports(m) {
            let dep = parser::get_module(&imp.path, &m.source_path)?;
            if !checkers::depused(&m, &dep) {
                return Err(format!("{}: imported {} is not used", m.id, dep.id));
            }
        }
    }

    // Convert all modules to C modules.
    let c_modules: Vec<nodes::CompatModule> = all_modules
        .iter()
        .map(|m| translator::translate(&m))
        .collect();

    // Decide where we'll stash all generated C code.
    let tmp_dir_path = format!("{}/tmp", parser::homepath());
    if fs::metadata(&tmp_dir_path).is_err() {
        fs::create_dir(&tmp_dir_path).unwrap();
    }

    // Write the generated C source files in the temp directory and build the
    // mapping of the generated C file path to the original source file path,
    // that will be used to trace C compiler's errors at least to the original
    // files.
    struct PathId {
        path: String,
        id: String,
    }
    let mut paths: Vec<PathId> = Vec::new();
    for module in &c_modules {
        let src = format::format_compat_module(&module);
        let path = format!("{}/{:x}.c", tmp_dir_path, md5::compute(&module.id));
        paths.push(PathId {
            path: String::from(&path),
            id: String::from(&module.id),
        });
        fs::write(&path, &src).unwrap();
    }

    // Determine the list of OS libraries to link. "m" is the library for code
    // in included <math.h>. For simplicity both the header and the library are
    // always included.
    // Other libraries are simply taked from the #link hints in the source code.
    let mut link: Vec<String> = vec!["m".to_string()];
    for module in &c_modules {
        for l in &module.link {
            if link.iter().position(|x| x == l).is_none() {
                link.push(l.clone());
            }
        }
    }

    let mut cmd = Command::new("c99");
    cmd.args(&[
        "-Wall",
        "-Wextra",
        "-Werror",
        "-pedantic",
        "-pedantic-errors",
        "-fmax-errors=1",
        "-Wno-parentheses",
        "-g",
    ]);
    for p in &paths {
        cmd.arg(p.path.clone());
    }
    cmd.args(&["-o", &output_name]);
    for l in link {
        cmd.args(&["-l", &l.trim()]);
    }
    cmd.stderr(Stdio::piped());
    let mut proc = cmd.spawn().unwrap();
    let out = proc.stderr.as_mut().unwrap();
    let reader = std::io::BufReader::new(out);
    for liner in reader.lines() {
        let mut line = liner.unwrap();
        for p in &paths {
            line = line.replace(&p.path, &format!("{} -> {}", &p.id, &p.path));
        }
        println!("{}", &line);
    }
    let r = proc.wait().unwrap();
    if r.success() {
        return Ok(());
    }
    return Err(String::from("build failed"));
}

fn build(argv: &[String]) -> Result<(), String> {
    if argv.len() < 1 || argv.len() > 2 {
        return Err(String::from("Usage: build <source-path> [<output-path>]"));
    }
    let path = &argv[0];
    let output_name = if argv.len() == 2 {
        argv[1].clone()
    } else {
        Path::new(&path)
            .with_extension("")
            .file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .to_string()
    };
    match build_prog(path, &output_name) {
        Ok(()) => exit(0),
        Err(s) => {
            eprintln!("{}", s);
            exit(1)
        }
    }
}

fn resolve_deps(m: &nodes::Module) -> Vec<nodes::Module> {
    let mut deps: Vec<nodes::Module> = vec![m.clone()];
    let mut present = vec![m.id.clone()];
    for imp in module_imports(&m) {
        let sub = parser::get_module(&imp.path, &m.source_path).unwrap();
        for dep in resolve_deps(&sub) {
            if present.contains(&&dep.id) {
                continue;
            }
            present.push(dep.id.clone());
            deps.push(dep);
        }
    }
    return deps;
}

struct Import {
    path: String,
}

fn module_imports(module: &nodes::Module) -> Vec<Import> {
    let mut list: Vec<Import> = vec![];
    for element in &module.elements {
        match element {
            nodes::ModuleObject::Import { path } => list.push(Import { path: path.clone() }),
            _ => {}
        }
    }
    return list;
}

fn deptree(argv: &[String]) -> i32 {
    if argv.len() != 1 {
        eprintln!("usage: deptree <source-path>");
        return 1;
    }
    let path = &argv[0];
    let m = get_first_module(path).unwrap();
    let tree = build_tree(&m);
    let r = render_tree(&tree);
    println!("{}", r.join("\n"));
    return 0;
}

struct DepNode {
    name: String,
    deps: Vec<DepNode>,
}

fn build_tree(m: &nodes::Module) -> DepNode {
    let imports = module_imports(m);
    let mut deps = vec![];
    for import in imports {
        let m = parser::get_module(&import.path, &m.source_path).unwrap();
        deps.push(build_tree(&m));
    }
    return DepNode {
        name: m.id.clone(),
        deps,
    };
}

fn render_tree(tree: &DepNode) -> Vec<String> {
    let mut lines: Vec<String> = vec![tree.name.clone()];
    let n = tree.deps.len();
    for (i, dep) in tree.deps.iter().enumerate() {
        let r = render_tree(&dep);
        if i == n - 1 {
            lines.append(&mut indent_tree(r, " └", "  "));
        } else {
            lines.append(&mut indent_tree(r, " ├", " │"));
        }
    }
    return lines;
}

fn indent_tree(lines: Vec<String>, first: &str, cont: &str) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();
    for (i, line) in lines.iter().enumerate() {
        if i == 0 {
            result.push(format!("{}{}", first, line))
        } else {
            result.push(format!("{}{}", cont, line));
        }
    }
    return result;
}

fn exports(argv: &[String]) -> i32 {
    for path in argv {
        let m = get_first_module(&path.to_string()).unwrap();
        println!("mod {}", m.id);
        let exports = checkers::get_exports(&m);
        if !exports.consts.is_empty() {
            println!("constants");
            for c in exports.consts {
                println!("\t{}", c.id);
            }
        }
        if !exports.types.is_empty() {
            println!("types");
            for c in exports.types {
                println!("\t{}", c.form.alias);
            }
        }
        if !exports.fns.is_empty() {
            println!("functions");
            for c in exports.fns {
                let mut params = String::from("(");
                for (i, parameter) in c.parameters.list.iter().enumerate() {
                    if i > 0 {
                        params += ", ";
                    }
                    params += &format::format_type(&parameter.type_name);
                    params += " ";
                    for form in &parameter.forms {
                        params += &format::format_form(&form);
                    }
                }
                if c.parameters.variadic {
                    params += ", ...";
                }
                params += ")";

                let form = format::format_form(&c.form);
                let mut s = String::new();
                s += &format!("{}\t{} {}", format::format_type(&c.type_name), form, params);
                println!("\t{}", s);
            }
        }
    }
    return 0;
}
<commit_msg>Tweak test output<commit_after>mod buf;
mod checkers;
mod format;
mod lexer;
mod nodes;
mod parser;
#[cfg(test)]
mod rename;
mod translator;
use md5;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::env;
use std::fs;
use std::io::BufRead;
use std::path::Path;
use std::process::{exit, Command, Stdio};
use std::str;
use std::string::String;

#[test]
fn test_rename() {
    let mut m = parser::get_module(&"json".to_string(), &String::from(".")).unwrap();
    let exports = checkers::get_exports(&m);
    let mut names: Vec<String> = Vec::new();
    for e in exports.consts {
        names.push(e.id);
    }
    for f in exports.fns {
        names.push(f.form.name);
    }
    for t in exports.types {
        names.push(t.form.alias);
    }
    println!("{:?}", names);
    rename::rename_mod(&mut m, &"kek".to_string(), &names);
    let c = translator::translate(&m);
    fs::write("out.c", format::format_compat_module(&c)).unwrap();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args[1] == "build" {
        match build(&args[2..]) {
            Ok(_) => exit(0),
            Err(m) => {
                eprintln!("{}", m);
                exit(1);
            }
        }
    }
    if args[1] == "deptree" {
        exit(deptree(&args[2..]));
    }
    if args[1] == "exports" {
        exit(exports(&args[2..]));
    }
    if args[1] == "test" {
        match run_tests(&args[2..]) {
            Err(s) => {
                eprintln!("{}", s);
                exit(1);
            }
            Ok(_) => {
                exit(0);
            }
        }
    }
    exit(1);
}

fn find_tests(dirpath: &String) -> Result<Vec<String>, String> {
    let mut paths: Vec<String> = Vec::new();
    for entry_result in fs::read_dir(dirpath).unwrap() {
        let result = entry_result.unwrap();
        let path = result.path();
        if path.to_str().unwrap().ends_with(".test.c") {
            paths.push(String::from(path.to_str().unwrap()));
        } else if path.is_dir() {
            paths.append(&mut find_tests(&String::from(path.to_str().unwrap())).unwrap())
        }
    }
    return Ok(paths);
}

fn run_tests(args: &[String]) -> Result<(), String> {
    let mut fails = 0;
    let mut total = 0;
    for arg in args {
        let tests = find_tests(arg)?;
        for path in tests {
            build_prog(&path, &String::from("test.out")).unwrap();
            let output = Command::new("./test.out").output().unwrap();
            let errstr = str::from_utf8(&output.stderr).unwrap();
            let outstr = str::from_utf8(&output.stdout).unwrap().trim_end();
            if output.status.success() {
                if outstr != "" {
                    println!("OK {}: {}", path, outstr);
                } else {
                    println!("OK {}", path);
                }
            } else {
                fails += 1;
                println!("FAIL {}", path);
                println!("stdout:\n{}", outstr);
            }
            if errstr != "" {
                println!("stderr:\n{}", errstr);
            }
            total += 1
        }
        println!("{} tests", total)
    }
    if fails > 1 {
        return Err(format!("{} tests failed", fails));
    }
    if fails == 1 {
        return Err(format!("1 test failed"));
    }
    return Ok(());
}

fn get_first_module(path: &String) -> Result<nodes::Module, String> {
    let name = String::from(Path::new(path).file_name().unwrap().to_str().unwrap());
    return parser::get_module(&name, &path);
}

#[test]
fn snapshots() {
    for entry in fs::read_dir("test/snapshots").unwrap() {
        let tmp = entry.unwrap().path();
        let path = tmp.to_str().unwrap();
        if path.ends_with(".out.c") {
            continue;
        }
        println!("{}", path);

        // get the output
        let m = get_first_module(&path.to_string()).unwrap();
        let mods = resolve_deps(&m);
        let c_mods: Vec<nodes::CompatModule> =
            mods.iter().map(|m| translator::translate(&m)).collect();
        let result = format::format_compat_module(&c_mods[0]);

        let snapshot_path = path.replace(".c", ".out.c");
        if env::var("UPDATE_SNAPSHOT").is_ok() {
            fs::write(snapshot_path, result).unwrap();
        } else {
            assert_eq!(result, fs::read_to_string(snapshot_path).unwrap());
        }
    }
}

fn build_prog(source_path: &String, output_name: &String) -> Result<(), String> {
    // Get the module we're building.
    let main_module = get_first_module(source_path)?;

    // Get all modules that our module depends on. This includes our module as
    // well, so this is a complete list of modules required for the build.
    let all_modules = resolve_deps(&main_module);

    // Dome some checks.
    for m in &all_modules {
        for imp in module_imports(m) {
            let dep = parser::get_module(&imp.path, &m.source_path)?;
            if !checkers::depused(&m, &dep) {
                return Err(format!("{}: imported {} is not used", m.id, dep.id));
            }
        }
    }

    // Convert all modules to C modules.
    let c_modules: Vec<nodes::CompatModule> = all_modules
        .iter()
        .map(|m| translator::translate(&m))
        .collect();

    // Decide where we'll stash all generated C code.
    let tmp_dir_path = format!("{}/tmp", parser::homepath());
    if fs::metadata(&tmp_dir_path).is_err() {
        fs::create_dir(&tmp_dir_path).unwrap();
    }

    // Write the generated C source files in the temp directory and build the
    // mapping of the generated C file path to the original source file path,
    // that will be used to trace C compiler's errors at least to the original
    // files.
    struct PathId {
        path: String,
        id: String,
    }
    let mut paths: Vec<PathId> = Vec::new();
    for module in &c_modules {
        let src = format::format_compat_module(&module);
        let path = format!("{}/{:x}.c", tmp_dir_path, md5::compute(&module.id));
        paths.push(PathId {
            path: String::from(&path),
            id: String::from(&module.id),
        });
        fs::write(&path, &src).unwrap();
    }

    // Determine the list of OS libraries to link. "m" is the library for code
    // in included <math.h>. For simplicity both the header and the library are
    // always included.
    // Other libraries are simply taked from the #link hints in the source code.
    let mut link: Vec<String> = vec!["m".to_string()];
    for module in &c_modules {
        for l in &module.link {
            if link.iter().position(|x| x == l).is_none() {
                link.push(l.clone());
            }
        }
    }

    let mut cmd = Command::new("c99");
    cmd.args(&[
        "-Wall",
        "-Wextra",
        "-Werror",
        "-pedantic",
        "-pedantic-errors",
        "-fmax-errors=1",
        "-Wno-parentheses",
        "-g",
    ]);
    for p in &paths {
        cmd.arg(p.path.clone());
    }
    cmd.args(&["-o", &output_name]);
    for l in link {
        cmd.args(&["-l", &l.trim()]);
    }
    cmd.stderr(Stdio::piped());
    let mut proc = cmd.spawn().unwrap();
    let out = proc.stderr.as_mut().unwrap();
    let reader = std::io::BufReader::new(out);
    for liner in reader.lines() {
        let mut line = liner.unwrap();
        for p in &paths {
            line = line.replace(&p.path, &format!("{} -> {}", &p.id, &p.path));
        }
        println!("{}", &line);
    }
    let r = proc.wait().unwrap();
    if r.success() {
        return Ok(());
    }
    return Err(String::from("build failed"));
}

fn build(argv: &[String]) -> Result<(), String> {
    if argv.len() < 1 || argv.len() > 2 {
        return Err(String::from("Usage: build <source-path> [<output-path>]"));
    }
    let path = &argv[0];
    let output_name = if argv.len() == 2 {
        argv[1].clone()
    } else {
        Path::new(&path)
            .with_extension("")
            .file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .to_string()
    };
    match build_prog(path, &output_name) {
        Ok(()) => exit(0),
        Err(s) => {
            eprintln!("{}", s);
            exit(1)
        }
    }
}

fn resolve_deps(m: &nodes::Module) -> Vec<nodes::Module> {
    let mut deps: Vec<nodes::Module> = vec![m.clone()];
    let mut present = vec![m.id.clone()];
    for imp in module_imports(&m) {
        let sub = parser::get_module(&imp.path, &m.source_path).unwrap();
        for dep in resolve_deps(&sub) {
            if present.contains(&&dep.id) {
                continue;
            }
            present.push(dep.id.clone());
            deps.push(dep);
        }
    }
    return deps;
}

struct Import {
    path: String,
}

fn module_imports(module: &nodes::Module) -> Vec<Import> {
    let mut list: Vec<Import> = vec![];
    for element in &module.elements {
        match element {
            nodes::ModuleObject::Import { path } => list.push(Import { path: path.clone() }),
            _ => {}
        }
    }
    return list;
}

fn deptree(argv: &[String]) -> i32 {
    if argv.len() != 1 {
        eprintln!("usage: deptree <source-path>");
        return 1;
    }
    let path = &argv[0];
    let m = get_first_module(path).unwrap();
    let tree = build_tree(&m);
    let r = render_tree(&tree);
    println!("{}", r.join("\n"));
    return 0;
}

struct DepNode {
    name: String,
    deps: Vec<DepNode>,
}

fn build_tree(m: &nodes::Module) -> DepNode {
    let imports = module_imports(m);
    let mut deps = vec![];
    for import in imports {
        let m = parser::get_module(&import.path, &m.source_path).unwrap();
        deps.push(build_tree(&m));
    }
    return DepNode {
        name: m.id.clone(),
        deps,
    };
}

fn render_tree(tree: &DepNode) -> Vec<String> {
    let mut lines: Vec<String> = vec![tree.name.clone()];
    let n = tree.deps.len();
    for (i, dep) in tree.deps.iter().enumerate() {
        let r = render_tree(&dep);
        if i == n - 1 {
            lines.append(&mut indent_tree(r, " └", "  "));
        } else {
            lines.append(&mut indent_tree(r, " ├", " │"));
        }
    }
    return lines;
}

fn indent_tree(lines: Vec<String>, first: &str, cont: &str) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();
    for (i, line) in lines.iter().enumerate() {
        if i == 0 {
            result.push(format!("{}{}", first, line))
        } else {
            result.push(format!("{}{}", cont, line));
        }
    }
    return result;
}

fn exports(argv: &[String]) -> i32 {
    for path in argv {
        let m = get_first_module(&path.to_string()).unwrap();
        println!("mod {}", m.id);
        let exports = checkers::get_exports(&m);
        if !exports.consts.is_empty() {
            println!("constants");
            for c in exports.consts {
                println!("\t{}", c.id);
            }
        }
        if !exports.types.is_empty() {
            println!("types");
            for c in exports.types {
                println!("\t{}", c.form.alias);
            }
        }
        if !exports.fns.is_empty() {
            println!("functions");
            for c in exports.fns {
                let mut params = String::from("(");
                for (i, parameter) in c.parameters.list.iter().enumerate() {
                    if i > 0 {
                        params += ", ";
                    }
                    params += &format::format_type(&parameter.type_name);
                    params += " ";
                    for form in &parameter.forms {
                        params += &format::format_form(&form);
                    }
                }
                if c.parameters.variadic {
                    params += ", ...";
                }
                params += ")";

                let form = format::format_form(&c.form);
                let mut s = String::new();
                s += &format!("{}\t{} {}", format::format_type(&c.type_name), form, params);
                println!("\t{}", s);
            }
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate board_game_geom as geom;
#[macro_use]
extern crate conrod;
extern crate find_folder;
extern crate piston_window;
extern crate vecmath;

use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use std::str::FromStr;

use geom::{Point, Size};

use conrod::{Button, Canvas, Circle, DropDownList, Frameable, Labelable, LineStyle, Rectangle,
             Sizeable, Text, Theme, Widget, WidgetMatrix};
use conrod::color::{self, Color, Colorable};
use conrod::Positionable;

use piston_window::{Glyphs, PistonWindow, UpdateEvent, WindowSettings};

use board::Board;
use othello_disk::OthelloDisk;

type Ui = conrod::Ui<Glyphs>;

mod board;
mod othello_disk;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Side {
    Black,
    White,
}

impl Side {
    fn flip(self) -> Side {
        match self {
            Side::Black => Side::White,
            Side::White => Side::Black,
        }
    }
}

#[derive(Clone, Debug)]
struct App {
    state: State,
    game_config: GameConfig,
    view_config: ViewConfig,
}

impl Default for App {
    fn default() -> App {
        App {
            state: State::Start(StartState::default()),
            game_config: GameConfig::default(),
            view_config: ViewConfig::default(),
        }
    }
}

#[derive(Clone, Debug)]
enum State {
    Start(StartState),
    Play(PlayState),
}

impl State {
    fn unwrap_start(&self) -> &StartState {
        match self {
            &State::Start(ref start_ref) => start_ref,
            _ => panic!(),
        }
    }

    fn unwrap_mut_start(&mut self) -> &mut StartState {
        match self {
            &mut State::Start(ref mut start_ref) => start_ref,
            _ => panic!(),
        }
    }

    fn unwrap_play(&self) -> &PlayState {
        match self {
            &State::Play(ref play_ref) => play_ref,
            _ => panic!(),
        }
    }

    fn unwrap_mut_play(&mut self) -> &mut PlayState {
        match self {
            &mut State::Play(ref mut play_ref) => play_ref,
            _ => panic!(),
        }
    }
}

#[derive(Clone, Debug)]
struct StartState {
    ddl_rows_selected_idx: Option<usize>,
    ddl_cols_selected_idx: Option<usize>,
    ddl_rows: Vec<String>,
    ddl_cols: Vec<String>,
}

impl Default for StartState {
    fn default() -> StartState {
        let ddl = (2..11).map(|n| n.to_string()).collect::<Vec<_>>();
        StartState {
            ddl_rows_selected_idx: ddl.iter().position(|x| x == "8"),
            ddl_cols_selected_idx: ddl.iter().position(|x| x == "8"),
            ddl_rows: ddl.clone(),
            ddl_cols: ddl,
        }

    }
}

#[derive(Clone, Debug)]
struct PlayState {
    board: Board,
}

impl PlayState {
    fn new(size: Size) -> PlayState {
        PlayState { board: Board::new(size) }
    }
}

#[derive(Copy, Clone, Debug)]
struct GameConfig {
    rows: i32,
    cols: i32,
}

impl Default for GameConfig {
    fn default() -> GameConfig {
        GameConfig { rows: 8, cols: 8 }
    }
}

#[derive(Copy, Clone, Debug)]
struct ViewConfig {
    frame_width: f64,
    cell_size: f64,
    disk_radius: f64,
    dot_radius: f64,
    board_margin: f64,
    indicator_text_width: f64,

    frame_color: Color,
    board_color: Color,
    white_color: Color,
    black_color: Color,
}

impl Default for ViewConfig {
    fn default() -> ViewConfig {
        ViewConfig {
            frame_width: 1.0,
            cell_size: 80.0,
            disk_radius: 32.0,
            dot_radius: 6.0,
            board_margin: 40.0,
            indicator_text_width: 90.0,

            frame_color: color::black(),
            board_color: color::rgba(0.0, 0.5, 0.0, 1.0),
            white_color: color::white(),
            black_color: color::black(),
        }
    }
}

fn main() {
    let window: PistonWindow = {
        WindowSettings::new("Othello", (1024, 768))
            .exit_on_esc(true)
            .vsync(true)
            .build()
            .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e))
    };

    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
                         .for_folder("assets")
                         .unwrap();
        let ref font_path = assets.join("FiraSans-Regular.ttf");
        let factory = window.factory.borrow().clone();
        let glyph_cache = Glyphs::new(font_path, factory).unwrap();
        let theme = Theme::default();
        Ui::new(glyph_cache, theme)
    };

    let app_ref = Rc::new(RefCell::new(App::default()));
    for event in window {
        ui.handle_event(&event);

        let _ = event.update(|_| ui.set_widgets(|ui| set_widgets(ui, app_ref.clone())));
        event.draw_2d(|c, g| ui.draw_if_changed(c, g));
    }
}

widget_ids! {
    CANVAS,

    START_BUTTON,
    TIMES_LABEL,
    ROWS_DDL,
    COLS_DDL,

    PLAY_CANVAS,
    BOARD,
    DOT with 4,
    INDICATOR_LABEL_ICON with 2,
    INDICATOR_LABEL_TEXT with 2,
}

fn set_widgets(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let func: fn(ui: &mut Ui, Rc<RefCell<App>>) = {
        let app = app_ref.deref().borrow();
        match app.state {
            State::Start(_) => set_widgets_start,
            State::Play(_) => set_widgets_play,
        }
    };
    func(ui, app_ref.clone())
}

fn set_widgets_start(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (gc, vc) = {
        let app = app_ref.deref().borrow();
        (app.game_config, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);
    Text::new(&"x")
        .w_h(30.0, 50.0)
        .font_size(40)
        .align_text_middle()
        .mid_top_with_margin_on(CANVAS, 40.0)
        .set(TIMES_LABEL, ui);

    {
        let mut app = app_ref.deref().borrow_mut();
        let mut rows = app.game_config.rows;
        let mut cols = app.game_config.cols;
        {
            let start = app.state.unwrap_mut_start();
            DropDownList::new(&mut start.ddl_rows, &mut start.ddl_rows_selected_idx)
                .w_h(50.0, 50.0)
                .left_from(TIMES_LABEL, 30.0)
                .label("Rows")
                .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
                    *selected_idx = Some(new_idx);
                    rows = i32::from_str(string).unwrap();
                })
                .set(ROWS_DDL, ui);
            DropDownList::new(&mut start.ddl_cols, &mut start.ddl_cols_selected_idx)
                .w_h(50.0, 50.0)
                .right_from(TIMES_LABEL, 30.0)
                .label("Cols")
                .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
                    *selected_idx = Some(new_idx);
                    cols = i32::from_str(string).unwrap();
                })
                .set(COLS_DDL, ui);
        }
        app.game_config.rows = rows;
        app.game_config.cols = cols;
    }

    Button::new()
        .w_h(200.0, 50.0)
        .down_from(TIMES_LABEL, 40.0)
        .align_middle_x_of(TIMES_LABEL)
        .label("start")
        .react(|| {
            let mut app = app_ref.deref().borrow_mut();
            app.state = State::Play(PlayState::new(Size(gc.rows, gc.cols)));
        })
        .set(START_BUTTON, ui);
}

fn set_widgets_play(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (gc, vc) = {
        let app = app_ref.deref().borrow();
        (app.game_config, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);

    let board_width = vc.cell_size * (gc.cols as f64);
    let indicator_width = vc.cell_size + vc.indicator_text_width;
    let width = board_width + vc.board_margin * 2.0 + indicator_width + vc.board_margin;

    let board_height = vc.cell_size * (gc.rows as f64);
    let indicator_height = vc.cell_size * 2.0;
    let height = vc.board_margin * 2.0 + f64::max(board_height, indicator_height);

    let style = LineStyle::new().thickness(0.0);
    let rect = Rectangle::outline_styled([width, height], style);

    match (ui.win_w < board_width, ui.win_h < board_height) {
        (true, true) => rect.top_left_of(CANVAS),
        (false, true) => rect.mid_top_of(CANVAS),
        (true, false) => rect.mid_left_of(CANVAS),
        (false, false) => rect.middle_of(CANVAS),
    }
    .set(PLAY_CANVAS, ui);

    WidgetMatrix::new(gc.cols as usize, gc.rows as usize)
        .top_left_with_margins_on(PLAY_CANVAS, vc.board_margin, vc.board_margin)
        .w_h(vc.cell_size * (gc.cols as f64),
             vc.cell_size * (gc.rows as f64))
        .each_widget(|_n, col, row| {
            let pt = Point(row as i32, col as i32);

            let app_ref = app_ref.clone();
            {
                let app = app_ref.deref().borrow();
                let play = app.state.unwrap_play();

                match play.board.turn() {
                    Some(turn) if play.board.can_locate(pt) => {
                        OthelloDisk::new().flow_disk(Some(turn))
                    }
                    _ => OthelloDisk::new(),
                }
                .disk(play.board[pt])
                .background_color(vc.board_color)
                .frame(vc.frame_width)
                .frame_color(vc.frame_color)
                .white_color(vc.white_color)
                .black_color(vc.black_color)
                .radius(vc.disk_radius)
            }
            .react(move || {
                let mut app = app_ref.deref().borrow_mut();
                let play = app.state.unwrap_mut_play();
                play.board.locate(pt);
            })
        })
        .set(BOARD, ui);

    let x = vc.cell_size * ((gc.cols / 4) as f64);
    let y = vc.cell_size * ((gc.rows / 4) as f64);
    let signs = &[(-1.0, 1.0), (1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)];
    for (i, &(sx, sy)) in signs.iter().enumerate() {
        Circle::fill(vc.dot_radius)
            .x_y_relative_to(BOARD, sx * x, sy * y)
            .color(vc.frame_color)
            .set(DOT + i, ui);
    }

    for (i, &side) in [Side::Black, Side::White].iter().enumerate() {
        let app = app_ref.deref().borrow();
        let play = app.state.unwrap_play();

        if i == 0 {
            OthelloDisk::new().right_from(BOARD, vc.board_margin)
        } else {
            OthelloDisk::new().down_from(INDICATOR_LABEL_ICON + (i - 1), 0.0)
        }
        .w_h(vc.cell_size, vc.cell_size)
        .background_color(vc.board_color)
        .frame(0.0)
        .white_color(vc.white_color)
        .black_color(vc.black_color)
        .radius(vc.disk_radius)
        .disk(Some(side))
        .react(|| {})
        .set(INDICATOR_LABEL_ICON + i, ui);

        Text::new(&play.board.num_disk(side).to_string())
            .w(vc.indicator_text_width)
            .right_from(INDICATOR_LABEL_ICON + i, 0.0)
            .font_size(60)
            .align_text_right()
            .set(INDICATOR_LABEL_TEXT + i, ui);
    }
}
<commit_msg>Use AsRef, AsMut<commit_after>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate board_game_geom as geom;
#[macro_use]
extern crate conrod;
extern crate find_folder;
extern crate piston_window;
extern crate vecmath;

use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use std::str::FromStr;

use geom::{Point, Size};

use conrod::{Button, Canvas, Circle, DropDownList, Frameable, Labelable, LineStyle, Rectangle,
             Sizeable, Text, Theme, Widget, WidgetMatrix};
use conrod::color::{self, Color, Colorable};
use conrod::Positionable;

use piston_window::{Glyphs, PistonWindow, UpdateEvent, WindowSettings};

use board::Board;
use othello_disk::OthelloDisk;

type Ui = conrod::Ui<Glyphs>;

mod board;
mod othello_disk;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Side {
    Black,
    White,
}

impl Side {
    fn flip(self) -> Side {
        match self {
            Side::Black => Side::White,
            Side::White => Side::Black,
        }
    }
}

#[derive(Clone, Debug)]
struct App {
    state: State,
    game_config: GameConfig,
    view_config: ViewConfig,
}

impl Default for App {
    fn default() -> App {
        App {
            state: State::Start(StartState::default()),
            game_config: GameConfig::default(),
            view_config: ViewConfig::default(),
        }
    }
}

#[derive(Clone, Debug)]
enum State {
    Start(StartState),
    Play(PlayState),
}

macro_rules! impl_state {
    ($state_ty:ty, $state_name:ident) => {
        impl AsRef<$state_ty> for State {
            fn as_ref(&self) -> &$state_ty {
                match self {
                    &State::$state_name(ref s) => s,
                    _ => panic!(),
                }
            }
        }
        impl AsMut<$state_ty> for State {
            fn as_mut(&mut self) -> &mut $state_ty {
                match self {
                    &mut State::$state_name(ref mut s) => s,
                    _ => panic!(),
                }
            }
        }
    }
}

impl_state!(StartState, Start);
impl_state!(PlayState, Play);

#[derive(Clone, Debug)]
struct StartState {
    ddl_rows_selected_idx: Option<usize>,
    ddl_cols_selected_idx: Option<usize>,
    ddl_rows: Vec<String>,
    ddl_cols: Vec<String>,
}

impl Default for StartState {
    fn default() -> StartState {
        let ddl = (2..11).map(|n| n.to_string()).collect::<Vec<_>>();
        StartState {
            ddl_rows_selected_idx: ddl.iter().position(|x| x == "8"),
            ddl_cols_selected_idx: ddl.iter().position(|x| x == "8"),
            ddl_rows: ddl.clone(),
            ddl_cols: ddl,
        }

    }
}

#[derive(Clone, Debug)]
struct PlayState {
    board: Board,
}

impl PlayState {
    fn new(size: Size) -> PlayState {
        PlayState { board: Board::new(size) }
    }
}

#[derive(Copy, Clone, Debug)]
struct GameConfig {
    rows: i32,
    cols: i32,
}

impl Default for GameConfig {
    fn default() -> GameConfig {
        GameConfig { rows: 8, cols: 8 }
    }
}

#[derive(Copy, Clone, Debug)]
struct ViewConfig {
    frame_width: f64,
    cell_size: f64,
    disk_radius: f64,
    dot_radius: f64,
    board_margin: f64,
    indicator_text_width: f64,

    frame_color: Color,
    board_color: Color,
    white_color: Color,
    black_color: Color,
}

impl Default for ViewConfig {
    fn default() -> ViewConfig {
        ViewConfig {
            frame_width: 1.0,
            cell_size: 80.0,
            disk_radius: 32.0,
            dot_radius: 6.0,
            board_margin: 40.0,
            indicator_text_width: 90.0,

            frame_color: color::black(),
            board_color: color::rgba(0.0, 0.5, 0.0, 1.0),
            white_color: color::white(),
            black_color: color::black(),
        }
    }
}

fn main() {
    let window: PistonWindow = {
        WindowSettings::new("Othello", (1024, 768))
            .exit_on_esc(true)
            .vsync(true)
            .build()
            .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e))
    };

    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
                         .for_folder("assets")
                         .unwrap();
        let ref font_path = assets.join("FiraSans-Regular.ttf");
        let factory = window.factory.borrow().clone();
        let glyph_cache = Glyphs::new(font_path, factory).unwrap();
        let theme = Theme::default();
        Ui::new(glyph_cache, theme)
    };

    let app_ref = Rc::new(RefCell::new(App::default()));
    for event in window {
        ui.handle_event(&event);

        let _ = event.update(|_| ui.set_widgets(|ui| set_widgets(ui, app_ref.clone())));
        event.draw_2d(|c, g| ui.draw_if_changed(c, g));
    }
}

widget_ids! {
    CANVAS,

    START_BUTTON,
    TIMES_LABEL,
    ROWS_DDL,
    COLS_DDL,

    PLAY_CANVAS,
    BOARD,
    DOT with 4,
    INDICATOR_LABEL_ICON with 2,
    INDICATOR_LABEL_TEXT with 2,
}

fn set_widgets(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let func: fn(ui: &mut Ui, Rc<RefCell<App>>) = {
        let app = app_ref.deref().borrow();
        match app.state {
            State::Start(_) => set_widgets_start,
            State::Play(_) => set_widgets_play,
        }
    };
    func(ui, app_ref.clone())
}

fn set_widgets_start(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (gc, vc) = {
        let app = app_ref.deref().borrow();
        (app.game_config, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);
    Text::new(&"x")
        .w_h(30.0, 50.0)
        .font_size(40)
        .align_text_middle()
        .mid_top_with_margin_on(CANVAS, 40.0)
        .set(TIMES_LABEL, ui);

    {
        let mut app = app_ref.deref().borrow_mut();
        let mut rows = app.game_config.rows;
        let mut cols = app.game_config.cols;
        {
            let start: &mut StartState = app.state.as_mut();
            DropDownList::new(&mut start.ddl_rows, &mut start.ddl_rows_selected_idx)
                .w_h(50.0, 50.0)
                .left_from(TIMES_LABEL, 30.0)
                .label("Rows")
                .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
                    *selected_idx = Some(new_idx);
                    rows = i32::from_str(string).unwrap();
                })
                .set(ROWS_DDL, ui);
            DropDownList::new(&mut start.ddl_cols, &mut start.ddl_cols_selected_idx)
                .w_h(50.0, 50.0)
                .right_from(TIMES_LABEL, 30.0)
                .label("Cols")
                .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
                    *selected_idx = Some(new_idx);
                    cols = i32::from_str(string).unwrap();
                })
                .set(COLS_DDL, ui);
        }
        app.game_config.rows = rows;
        app.game_config.cols = cols;
    }

    Button::new()
        .w_h(200.0, 50.0)
        .down_from(TIMES_LABEL, 40.0)
        .align_middle_x_of(TIMES_LABEL)
        .label("start")
        .react(|| {
            let mut app = app_ref.deref().borrow_mut();
            app.state = State::Play(PlayState::new(Size(gc.rows, gc.cols)));
        })
        .set(START_BUTTON, ui);
}

fn set_widgets_play(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (gc, vc) = {
        let app = app_ref.deref().borrow();
        (app.game_config, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);

    let board_width = vc.cell_size * (gc.cols as f64);
    let indicator_width = vc.cell_size + vc.indicator_text_width;
    let width = board_width + vc.board_margin * 2.0 + indicator_width + vc.board_margin;

    let board_height = vc.cell_size * (gc.rows as f64);
    let indicator_height = vc.cell_size * 2.0;
    let height = vc.board_margin * 2.0 + f64::max(board_height, indicator_height);

    let style = LineStyle::new().thickness(0.0);
    let rect = Rectangle::outline_styled([width, height], style);

    match (ui.win_w < board_width, ui.win_h < board_height) {
        (true, true) => rect.top_left_of(CANVAS),
        (false, true) => rect.mid_top_of(CANVAS),
        (true, false) => rect.mid_left_of(CANVAS),
        (false, false) => rect.middle_of(CANVAS),
    }
    .set(PLAY_CANVAS, ui);

    WidgetMatrix::new(gc.cols as usize, gc.rows as usize)
        .top_left_with_margins_on(PLAY_CANVAS, vc.board_margin, vc.board_margin)
        .w_h(vc.cell_size * (gc.cols as f64),
             vc.cell_size * (gc.rows as f64))
        .each_widget(|_n, col, row| {
            let pt = Point(row as i32, col as i32);

            let app_ref = app_ref.clone();
            {
                let app = app_ref.deref().borrow();
                let play: &PlayState = app.state.as_ref();

                match play.board.turn() {
                    Some(turn) if play.board.can_locate(pt) => {
                        OthelloDisk::new().flow_disk(Some(turn))
                    }
                    _ => OthelloDisk::new(),
                }
                .disk(play.board[pt])
                .background_color(vc.board_color)
                .frame(vc.frame_width)
                .frame_color(vc.frame_color)
                .white_color(vc.white_color)
                .black_color(vc.black_color)
                .radius(vc.disk_radius)
            }
            .react(move || {
                let mut app = app_ref.deref().borrow_mut();
                let play: &mut PlayState = app.state.as_mut();
                play.board.locate(pt);
            })
        })
        .set(BOARD, ui);

    let x = vc.cell_size * ((gc.cols / 4) as f64);
    let y = vc.cell_size * ((gc.rows / 4) as f64);
    let signs = &[(-1.0, 1.0), (1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)];
    for (i, &(sx, sy)) in signs.iter().enumerate() {
        Circle::fill(vc.dot_radius)
            .x_y_relative_to(BOARD, sx * x, sy * y)
            .color(vc.frame_color)
            .set(DOT + i, ui);
    }

    for (i, &side) in [Side::Black, Side::White].iter().enumerate() {
        let app = app_ref.deref().borrow();
        let play: &PlayState = app.state.as_ref();

        if i == 0 {
            OthelloDisk::new().right_from(BOARD, vc.board_margin)
        } else {
            OthelloDisk::new().down_from(INDICATOR_LABEL_ICON + (i - 1), 0.0)
        }
        .w_h(vc.cell_size, vc.cell_size)
        .background_color(vc.board_color)
        .frame(0.0)
        .white_color(vc.white_color)
        .black_color(vc.black_color)
        .radius(vc.disk_radius)
        .disk(Some(side))
        .react(|| {})
        .set(INDICATOR_LABEL_ICON + i, ui);

        Text::new(&play.board.num_disk(side).to_string())
            .w(vc.indicator_text_width)
            .right_from(INDICATOR_LABEL_ICON + i, 0.0)
            .font_size(60)
            .align_text_right()
            .set(INDICATOR_LABEL_TEXT + i, ui);
    }
}
<|endoftext|>