<commit_before>#![allow(dead_code)]
#![feature(unsafe_no_drop_flag)]
#![feature(str_char)]
#![feature(stmt_expr_attributes)]
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", feature(stmt_expr_attributes))]

#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate rand;

#[macro_use]
extern crate log;

extern crate log4rs;

extern crate num_cpus;

extern crate rustc_serialize;

extern crate toml;

extern crate crossbeam;

extern crate tar;

#[cfg(test)]
extern crate quickcheck;

mod config;
mod player;
mod zobrist;
mod cell;
mod field;
mod wave_pruning;
mod trajectories_pruning;
mod common;
mod uct;
mod heuristic;
mod minimax;
mod bot;
mod dfa;
mod spiral;
mod patterns;

#[cfg(test)]
mod field_test;

use std::io;
use std::io::{Write, BufReader, BufRead};
use std::str::FromStr;
use std::path::Path;
use std::fs::File;
use std::sync::Arc;
use log4rs::toml::Creator;
use player::Player;
use bot::Bot;
use patterns::Patterns;

const CONFIG_PATH: &'static str = "config/config.toml";

const LOG_CONFIG_PATH: &'static str = "config/log.toml";

const PATTERNS_PATH: &'static str = "patterns.tar";

fn write_author<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} author kurnevsky_evgeny", id).ok();
}

fn write_author_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} author", id).ok();
}

fn write_init<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} init", id).ok();
}

fn write_init_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} init", id).ok();
}

fn write_gen_move<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} gen_move {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_gen_move_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} gen_move", id).ok();
}

fn write_gen_move_with_complexity<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} gen_move_with_complexity {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_gen_move_with_complexity_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} gen_move_with_complexity", id).ok();
}

fn write_gen_move_with_time<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} gen_move_with_time {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_gen_move_with_time_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} gen_move_with_time", id).ok();
}

fn write_license<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} license AGPLv3+", id).ok();
}

fn write_license_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} license", id).ok();
}

fn write_list_commands<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} list_commands gen_move gen_move_with_complexity gen_move_with_time init list_commands name play quit undo version", id).ok();
}

fn write_list_commands_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} list_commands", id).ok();
}

fn write_name<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} name opai-rust", id).ok();
}

fn write_name_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} name", id).ok();
}

fn write_play<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} play {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_play_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} play", id).ok();
}

fn write_quit<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} quit", id).ok();
}

fn write_quit_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} quit", id).ok();
}

fn write_undo<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} undo", id).ok();
}

fn write_undo_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} undo", id).ok();
}

fn write_version<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} version {1}", id, env!("CARGO_PKG_VERSION")).ok();
}

fn write_version_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} version", id).ok();
}

fn write_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} input_error", id).ok();
}

fn main() {
  log4rs::init_file(Path::new(LOG_CONFIG_PATH), Creator::default()).ok();
  config::init();
  if let Some(mut config_file) = File::open(CONFIG_PATH).ok() {
    config::read(&mut config_file);
  } else if let Some(mut config_file) = File::create(CONFIG_PATH).ok() {
    config::write(&mut config_file);
  }
  let patterns = Arc::new(if let Some(patterns_file) = File::open(PATTERNS_PATH).ok() {
    Patterns::load(patterns_file)
  } else {
    Patterns::empty()
  });
  let mut input = BufReader::new(io::stdin());
  let mut output = io::stdout();
  let mut bot_option = None;
  let mut s = String::new();
  loop {
    s.clear();
    input.read_line(&mut s).ok();
    s.pop();
    let mut split = s.split(' ').fuse();
    if let Some(id) = split.next().and_then(|id_str| u32::from_str(id_str).ok()) {
      match split.next() {
        Some("author") => {
          if split.next().is_some() {
            write_author_error(&mut output, id);
          } else {
            write_author(&mut output, id);
          }
        },
        Some("init") => {
          let x_option = split.next().and_then(|x_str| u32::from_str(x_str).ok());
          let y_option = split.next().and_then(|y_str| u32::from_str(y_str).ok());
          let seed_option = split.next().and_then(|seed_str| u64::from_str(seed_str).ok());
          if split.next().is_some() {
            write_init_error(&mut output, id);
          } else if let (Some(x), Some(y), Some(seed)) = (x_option, y_option, seed_option) {
            bot_option = Some(Bot::new(x, y, seed, patterns.clone()));
            write_init(&mut output, id);
          } else {
            write_init_error(&mut output, id);
          }
        },
        Some("gen_move") => {
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          if split.next().is_some() {
            write_gen_move_error(&mut output, id);
          } else if let (Some(player), Some(bot)) = (player_option, bot_option.as_mut()) {
            if let Some((x, y)) = bot.best_move(player) {
              write_gen_move(&mut output, id, x, y, player);
            } else {
              write_gen_move_error(&mut output, id);
            }
          } else {
            write_gen_move_error(&mut output, id);
          }
        },
        Some("gen_move_with_complexity") => {
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          let complexity_option = split.next().and_then(|complexity_str| u32::from_str(complexity_str).ok() );
          if split.next().is_some() {
            write_gen_move_with_complexity_error(&mut output, id);
          } else if let (Some(player), Some(complexity), Some(bot)) = (player_option, complexity_option, bot_option.as_mut()) {
            if let Some((x, y)) = bot.best_move_with_complexity(player, complexity) {
              write_gen_move_with_complexity(&mut output, id, x, y, player);
            } else {
              write_gen_move_with_complexity_error(&mut output, id);
            }
          } else {
            write_gen_move_with_complexity_error(&mut output, id);
          }
        },
        Some("gen_move_with_time") => {
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          let time_option = split.next().and_then(|time_str| u32::from_str(time_str).ok() );
          if split.next().is_some() {
            write_gen_move_with_time_error(&mut output, id);
          } else if let (Some(player), Some(time), Some(bot)) = (player_option, time_option, bot_option.as_mut()) {
            if let Some((x, y)) = bot.best_move_with_time(player, time) {
              write_gen_move_with_time(&mut output, id, x, y, player);
            } else {
              write_gen_move_with_time_error(&mut output, id);
            }
          } else {
            write_gen_move_with_time_error(&mut output, id);
          }
        },
        Some("license") => {
          if split.next().is_some() {
            write_license_error(&mut output, id);
          } else {
            write_license(&mut output, id);
          }
        },
        Some("list_commands") => {
          if split.next().is_some() {
            write_list_commands_error(&mut output, id);
          } else {
            write_list_commands(&mut output, id);
          }
        },
        Some("name") => {
          if split.next().is_some() {
            write_name_error(&mut output, id);
          } else {
            write_name(&mut output, id);
          }
        },
        Some("play") => {
          let x_option = split.next().and_then(|x_str| u32::from_str(x_str).ok());
          let y_option = split.next().and_then(|y_str| u32::from_str(y_str).ok());
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          if split.next().is_some() {
            write_play_error(&mut output, id);
          } else if let (Some(x), Some(y), Some(player), Some(bot)) = (x_option, y_option, player_option, bot_option.as_mut()) {
            if bot.put_point(x, y, player) {
              write_play(&mut output, id, x, y, player);
            } else {
              write_play_error(&mut output, id);
            }
          } else {
            write_play_error(&mut output, id);
          }
        },
        Some("quit") => {
          if split.next().is_some() {
            write_quit_error(&mut output, id);
          } else {
            write_quit(&mut output, id);
            output.flush().ok();
            break;
          }
        },
        Some("undo") => {
          if split.next().is_some() {
            write_undo_error(&mut output, id);
          } else if let Some(bot) = bot_option.as_mut() {
            if bot.undo() {
              write_undo(&mut output, id);
            } else {
              write_undo_error(&mut output, id);
            }
          } else {
            write_undo_error(&mut output, id);
          }
        },
        Some("version") => {
          if split.next().is_some() {
            write_version_error(&mut output, id);
          } else {
            write_version(&mut output, id);
          }
        },
        _ => {
          write_error(&mut output, id);
        }
      }
    } else {
      write_error(&mut output, 0);
    }
    output.flush().ok();
  }
}
<commit_msg>Small fix.<commit_after>#![allow(dead_code)]
#![feature(unsafe_no_drop_flag)]
#![feature(str_char)]
#![feature(stmt_expr_attributes)]
#![cfg_attr(feature="clippy", feature(plugin))]

#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate rand;

#[macro_use]
extern crate log;

extern crate log4rs;

extern crate num_cpus;

extern crate rustc_serialize;

extern crate toml;

extern crate crossbeam;

extern crate tar;

#[cfg(test)]
extern crate quickcheck;

mod config;
mod player;
mod zobrist;
mod cell;
mod field;
mod wave_pruning;
mod trajectories_pruning;
mod common;
mod uct;
mod heuristic;
mod minimax;
mod bot;
mod dfa;
mod spiral;
mod patterns;

#[cfg(test)]
mod field_test;

use std::io;
use std::io::{Write, BufReader, BufRead};
use std::str::FromStr;
use std::path::Path;
use std::fs::File;
use std::sync::Arc;
use log4rs::toml::Creator;
use player::Player;
use bot::Bot;
use patterns::Patterns;

const CONFIG_PATH: &'static str = "config/config.toml";

const LOG_CONFIG_PATH: &'static str = "config/log.toml";

const PATTERNS_PATH: &'static str = "patterns.tar";

fn write_author<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} author kurnevsky_evgeny", id).ok();
}

fn write_author_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} author", id).ok();
}

fn write_init<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} init", id).ok();
}

fn write_init_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} init", id).ok();
}

fn write_gen_move<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} gen_move {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_gen_move_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} gen_move", id).ok();
}

fn write_gen_move_with_complexity<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} gen_move_with_complexity {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_gen_move_with_complexity_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} gen_move_with_complexity", id).ok();
}

fn write_gen_move_with_time<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} gen_move_with_time {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_gen_move_with_time_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} gen_move_with_time", id).ok();
}

fn write_license<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} license AGPLv3+", id).ok();
}

fn write_license_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} license", id).ok();
}

fn write_list_commands<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} list_commands gen_move gen_move_with_complexity gen_move_with_time init list_commands name play quit undo version", id).ok();
}

fn write_list_commands_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} list_commands", id).ok();
}

fn write_name<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} name opai-rust", id).ok();
}

fn write_name_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} name", id).ok();
}

fn write_play<T: Write>(output: &mut T, id: u32, x: u32, y: u32, player: Player) {
  writeln!(output, "= {0} play {1} {2} {3}", id, x, y, player.to_bool() as u32).ok();
}

fn write_play_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} play", id).ok();
}

fn write_quit<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} quit", id).ok();
}

fn write_quit_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} quit", id).ok();
}

fn write_undo<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} undo", id).ok();
}

fn write_undo_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} undo", id).ok();
}

fn write_version<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "= {0} version {1}", id, env!("CARGO_PKG_VERSION")).ok();
}

fn write_version_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} version", id).ok();
}

fn write_error<T: Write>(output: &mut T, id: u32) {
  writeln!(output, "? {0} input_error", id).ok();
}

fn main() {
  log4rs::init_file(Path::new(LOG_CONFIG_PATH), Creator::default()).ok();
  config::init();
  if let Some(mut config_file) = File::open(CONFIG_PATH).ok() {
    config::read(&mut config_file);
  } else if let Some(mut config_file) = File::create(CONFIG_PATH).ok() {
    config::write(&mut config_file);
  }
  let patterns = Arc::new(if let Some(patterns_file) = File::open(PATTERNS_PATH).ok() {
    Patterns::load(patterns_file)
  } else {
    Patterns::empty()
  });
  let mut input = BufReader::new(io::stdin());
  let mut output = io::stdout();
  let mut bot_option = None;
  let mut s = String::new();
  loop {
    s.clear();
    input.read_line(&mut s).ok();
    s.pop();
    let mut split = s.split(' ').fuse();
    if let Some(id) = split.next().and_then(|id_str| u32::from_str(id_str).ok()) {
      match split.next() {
        Some("author") => {
          if split.next().is_some() {
            write_author_error(&mut output, id);
          } else {
            write_author(&mut output, id);
          }
        },
        Some("init") => {
          let x_option = split.next().and_then(|x_str| u32::from_str(x_str).ok());
          let y_option = split.next().and_then(|y_str| u32::from_str(y_str).ok());
          let seed_option = split.next().and_then(|seed_str| u64::from_str(seed_str).ok());
          if split.next().is_some() {
            write_init_error(&mut output, id);
          } else if let (Some(x), Some(y), Some(seed)) = (x_option, y_option, seed_option) {
            bot_option = Some(Bot::new(x, y, seed, patterns.clone()));
            write_init(&mut output, id);
          } else {
            write_init_error(&mut output, id);
          }
        },
        Some("gen_move") => {
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          if split.next().is_some() {
            write_gen_move_error(&mut output, id);
          } else if let (Some(player), Some(bot)) = (player_option, bot_option.as_mut()) {
            if let Some((x, y)) = bot.best_move(player) {
              write_gen_move(&mut output, id, x, y, player);
            } else {
              write_gen_move_error(&mut output, id);
            }
          } else {
            write_gen_move_error(&mut output, id);
          }
        },
        Some("gen_move_with_complexity") => {
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          let complexity_option = split.next().and_then(|complexity_str| u32::from_str(complexity_str).ok() );
          if split.next().is_some() {
            write_gen_move_with_complexity_error(&mut output, id);
          } else if let (Some(player), Some(complexity), Some(bot)) = (player_option, complexity_option, bot_option.as_mut()) {
            if let Some((x, y)) = bot.best_move_with_complexity(player, complexity) {
              write_gen_move_with_complexity(&mut output, id, x, y, player);
            } else {
              write_gen_move_with_complexity_error(&mut output, id);
            }
          } else {
            write_gen_move_with_complexity_error(&mut output, id);
          }
        },
        Some("gen_move_with_time") => {
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          let time_option = split.next().and_then(|time_str| u32::from_str(time_str).ok() );
          if split.next().is_some() {
            write_gen_move_with_time_error(&mut output, id);
          } else if let (Some(player), Some(time), Some(bot)) = (player_option, time_option, bot_option.as_mut()) {
            if let Some((x, y)) = bot.best_move_with_time(player, time) {
              write_gen_move_with_time(&mut output, id, x, y, player);
            } else {
              write_gen_move_with_time_error(&mut output, id);
            }
          } else {
            write_gen_move_with_time_error(&mut output, id);
          }
        },
        Some("license") => {
          if split.next().is_some() {
            write_license_error(&mut output, id);
          } else {
            write_license(&mut output, id);
          }
        },
        Some("list_commands") => {
          if split.next().is_some() {
            write_list_commands_error(&mut output, id);
          } else {
            write_list_commands(&mut output, id);
          }
        },
        Some("name") => {
          if split.next().is_some() {
            write_name_error(&mut output, id);
          } else {
            write_name(&mut output, id);
          }
        },
        Some("play") => {
          let x_option = split.next().and_then(|x_str| u32::from_str(x_str).ok());
          let y_option = split.next().and_then(|y_str| u32::from_str(y_str).ok());
          let player_option = split.next().and_then(|player_str| u32::from_str(player_str).ok()).and_then(|player_u32| match player_u32 { //TODO: from_number method
            0 => Some(Player::Red),
            1 => Some(Player::Black),
            _ => None
          });
          if split.next().is_some() {
            write_play_error(&mut output, id);
          } else if let (Some(x), Some(y), Some(player), Some(bot)) = (x_option, y_option, player_option, bot_option.as_mut()) {
            if bot.put_point(x, y, player) {
              write_play(&mut output, id, x, y, player);
            } else {
              write_play_error(&mut output, id);
            }
          } else {
            write_play_error(&mut output, id);
          }
        },
        Some("quit") => {
          if split.next().is_some() {
            write_quit_error(&mut output, id);
          } else {
            write_quit(&mut output, id);
            output.flush().ok();
            break;
          }
        },
        Some("undo") => {
          if split.next().is_some() {
            write_undo_error(&mut output, id);
          } else if let Some(bot) = bot_option.as_mut() {
            if bot.undo() {
              write_undo(&mut output, id);
            } else {
              write_undo_error(&mut output, id);
            }
          } else {
            write_undo_error(&mut output, id);
          }
        },
        Some("version") => {
          if split.next().is_some() {
            write_version_error(&mut output, id);
          } else {
            write_version(&mut output, id);
          }
        },
        _ => {
          write_error(&mut output, id);
        }
      }
    } else {
      write_error(&mut output, 0);
    }
    output.flush().ok();
  }
}
<|endoftext|>


<commit_before>#![recursion_limit="128"]

use std::io;
use std::io::*;
use std::io::prelude::*;
use std::fs::File;
use std::fs;
use std::process::Command;
use std::collections::HashMap;
use std::str;

use std::io::Cursor;
use std::env;

#[macro_use]
extern crate nom;
extern crate byteorder;
extern crate clap;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use clap::{Arg, App, SubCommand, ArgMatches};

use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use nom::*;
use datfiles::parser::ParserSerializable;

#[macro_use]
mod datfiles;
mod levelexp;
mod itemtype;
mod magictype;

fn get_app_usage<'a>() -> ArgMatches<'a> {
    App::new("CO V5165 Toolkit")
        .version("0.3.0")
        .author("Tarouka <tarouka@openmailbox.org>")

        .subcommand(SubCommand::with_name("decrypt_dat")
            .about("Decrypts a standard CO dat file (itemtype.dat, Monster.dat or MagicType.dat).")
            .arg(Arg::with_name("SRC_FILENAME").help("Source filename").required(true))
            .arg(Arg::with_name("DST_FILENAME").help("Destination filename").required(true))
        )

        .subcommand(SubCommand::with_name("encrypt_dat")
            .about("Encrypts a standard CO dat file (itemtype.dat, Monster.dat or MagicType.dat).")
            .arg(Arg::with_name("SRC_FILENAME").help("Source filename").required(true))
            .arg(Arg::with_name("DST_FILENAME").help("Destination filename").required(true))
        )

        .subcommand(SubCommand::with_name("itemtype")
            .about("Encodes or decodes an itemtype file to a parseable format.")

            .subcommand(SubCommand::with_name("decode")
                .about("Decodes an itemtype.dat file to a more workable format.")

                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes JSON by default"))
                .arg(Arg::with_name("decrypt").long("decrypt").short("d").help("The file will be decrypted before processing"))
                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
            )

            .subcommand(SubCommand::with_name("encode")
                .about("Encodes back an itemtype.dat decoded format.")

                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes the format from the extension by default"))
                .arg(Arg::with_name("encrypt").long("encrypt").short("e").help("The file will be encrypted"))
            )
        )

        .subcommand(SubCommand::with_name("magictype")
            .about("Encodes or decodes an magictype file to a parseable format.")

            .subcommand(SubCommand::with_name("decode")
                .about("Decodes an magictype.dat file to a more workable format.")

                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes JSON by default"))
                .arg(Arg::with_name("decrypt").long("decrypt").short("d").help("The file will be decrypted before processing"))
                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
            )

            .subcommand(SubCommand::with_name("encode")
                .about("Encodes back an magictype.dat decoded format.")

                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes the format from the extension by default"))
                .arg(Arg::with_name("encrypt").long("encrypt").short("e").help("The file will be encrypted"))
            )
        )

        .get_matches()

}

fn main() {
    let matches = get_app_usage();

    if let Some(matches) = matches.subcommand_matches("decrypt_dat") {
        prepare_decrypt_dat(&matches);
    }

    else if let Some(matches) = matches.subcommand_matches("encrypt_dat") {
        prepare_encrypt_dat(&matches);
    }

    else if let Some(matches) = matches.subcommand_matches("itemtype") {
        if let Some(matches) = matches.subcommand_matches("decode") {
            prepare_itemtype_decode(&matches);
        }

        if let Some(matches) = matches.subcommand_matches("encode") {
            prepare_itemtype_encode(&matches);
        }
    }

    else if let Some(matches) = matches.subcommand_matches("magictype") {
        if let Some(matches) = matches.subcommand_matches("decode") {
            prepare_magictype_decode(&matches);
        }

        if let Some(matches) = matches.subcommand_matches("encode") {
            prepare_magictype_encode(&matches);
        }
    }

    else {
        println!("{}", matches.usage());
    }
}

fn prepare_decrypt_dat<'a>(matches: &'a ArgMatches) {
    let src_filename = matches.value_of("SRC_FILENAME").unwrap();
    let dst_filename = matches.value_of("DST_FILENAME").unwrap();

    exec_decrypt_dat(&src_filename, &dst_filename);
}

fn exec_decrypt_dat(source: &str, dest: &str) {
    let cofac_key = datfiles::generate_cofac_key();
    println!("Generated COFAC key successfully!");

    let bytes_read = read_all_bytes(source);
    println!("File successfully read.");

    let bytes_dec = datfiles::decrypt_bytes(&bytes_read, &cofac_key);
    println!("Decryption complete.");

    write_all_bytes(dest, bytes_dec);
    println!("Wrote decrypted file to {} successfully.", dest);
}

fn prepare_encrypt_dat<'a>(matches: &'a ArgMatches) {
    let src_filename = matches.value_of("SRC_FILENAME").unwrap();
    let dst_filename = matches.value_of("DST_FILENAME").unwrap();

    exec_encrypt_dat(&src_filename, &dst_filename);
}

fn exec_encrypt_dat(source: &str, dest: &str) {
    let cofac_key = datfiles::generate_cofac_key();
    println!("Generated COFAC key successfully!");

    let bytes_read = read_all_bytes(source);
    println!("File successfully read.");

    let bytes_dec = datfiles::encrypt_bytes(&bytes_read, &cofac_key);
    println!("Encryption complete.");

    write_all_bytes(dest, bytes_dec);
    println!("Wrote encrypted file to {} successfully.", dest);
}

fn prepare_itemtype_decode<'a>(matches: &'a ArgMatches) {
    let src_filename = matches.value_of("FROM_FILE").unwrap();
    let dst_filename = matches.value_of("TO_FILE").unwrap();
    let format = matches.value_of("format").unwrap_or("json");
    let decrypt = matches.is_present("decrypt");

    let src_bytes = read_all_bytes(&src_filename);

    let mut decrypted_bytes = read_all_bytes(&src_filename);

    if decrypt {
        let cofac_key = datfiles::generate_cofac_key();
        decrypted_bytes = datfiles::decrypt_bytes(&decrypted_bytes, &cofac_key);
    }

    let parsed_file = itemtype::parser::parse_item_type(&decrypted_bytes);

    let mut decoded_bytes: Vec<u8> = Vec::new();

    match parsed_file {
        Some(item_type) => {
            if format == "json" {
                decoded_bytes = itemtype::encoder::decode_item_type_to_json(&item_type);
            }
        },

        None => {
            println!("error parsing file");
        }
    }

    let mut bytes_to_write = decoded_bytes;

    write_all_bytes(&dst_filename, bytes_to_write);
}

fn prepare_itemtype_encode<'a>(matches: &'a ArgMatches) {
    let src_filename = matches.value_of("FROM_FILE").unwrap();
    let dst_filename = matches.value_of("TO_FILE").unwrap();
    let format = matches.value_of("format").unwrap_or("json");
    let encrypt = matches.is_present("encrypt");

    let src_bytes = read_all_bytes(&src_filename);
    let decoded_file = itemtype::encoder::encode_item_type_from_json(src_bytes);

    let mut encoded_bytes: Vec<u8> = Vec::new();

    if format == "json" {
        encoded_bytes = decoded_file.serialize_to_string().into_bytes();
    }

    let mut bytes_to_write = encoded_bytes;

    if encrypt {
        let cofac_key = datfiles::generate_cofac_key();
        bytes_to_write = datfiles::encrypt_bytes(&bytes_to_write, &cofac_key);
    }

    write_all_bytes(&dst_filename, bytes_to_write);
}

fn prepare_magictype_decode<'a>(matches: &'a ArgMatches) {
    let src_filename = matches.value_of("FROM_FILE").unwrap();
    let dst_filename = matches.value_of("TO_FILE").unwrap();
    let format = matches.value_of("format").unwrap_or("json");
    let decrypt = matches.is_present("decrypt");

    let mut decrypted_bytes = read_all_bytes(&src_filename);

    if decrypt {
        let cofac_key = datfiles::generate_cofac_key();
        decrypted_bytes = datfiles::decrypt_bytes(&decrypted_bytes, &cofac_key);
    }

    let parsed_file = magictype::parser::parse_magic_type(&decrypted_bytes);

    let mut decoded_bytes: Vec<u8> = Vec::new();

    match parsed_file {
        Some(magic_type) => {
            if format == "json" {
                decoded_bytes = magictype::encoder::decode_magic_type_to_json(&magic_type);
            }
        },

        None => {
            println!("error parsing file");
        }
    }

    write_all_bytes(&dst_filename, decoded_bytes);
}

fn prepare_magictype_encode<'a>(matches: &'a ArgMatches) {
    let src_filename = matches.value_of("FROM_FILE").unwrap();
    let dst_filename = matches.value_of("TO_FILE").unwrap();
    let format = matches.value_of("format").unwrap_or("json");
    let encrypt = matches.is_present("encrypt");

    let src_bytes = read_all_bytes(&src_filename);
    let decoded_file = magictype::encoder::encode_magic_type_from_json(src_bytes);

    let mut encoded_bytes: Vec<u8> = Vec::new();

    if format == "json" {
        encoded_bytes = decoded_file.serialize_to_string().into_bytes();
    }

    let mut bytes_to_write = encoded_bytes;

    if encrypt {
        let cofac_key = datfiles::generate_cofac_key();
        bytes_to_write = datfiles::encrypt_bytes(&bytes_to_write, &cofac_key);
    }

    write_all_bytes(&dst_filename, bytes_to_write);
}

fn read_all_bytes(filename: &str) -> Vec<u8> {
    let mut f = File::open(filename).unwrap();
    let mut buffer = Vec::new();

    let bytes_read = f.read_to_end(&mut buffer).unwrap();

    buffer
}

fn write_all_bytes(filename: &str, bytes: Vec<u8>) {
    let mut f = File::create(filename).unwrap();

    f.write_all(&bytes);
}

/*fn read_all_maps() {
    let maps_folder = "";
    let maps_folder_content = fs::read_dir(maps_folder).unwrap();
    let mut maps_store: Vec<u8>;
    let mut maps: Vec<maps::Map> = Vec::new();

    for map_filename in maps_folder_content {
        let map_filename_unwrapped = map_filename.unwrap().path();
        let map_filename_str = map_filename_unwrapped.to_str();
        let mut map_buff: Vec<u8> = Vec::new();

        match map_filename_str {
            Some(map_filename_actual) => {
                println!("Name: {}", map_filename_actual);
                let buff = maps::read_map_bytes(map_filename_actual);

                match maps::parse_map(&buff) {
                    Some(map) => {
                        println!(" - Map Width: {}", map.get_width());
                        println!(" - Map Height: {}", map.get_height());

                        maps.push(map);
                    },
                    None => {
                        println!("Failed to read map");
                    }
                }
            },
            None => {
                println!("File not found");
            }
        }
    }

    let mut counter_accessible: u64 = 0;
    let mut counter_inaccessible: u64 = 0;

    for map in maps {
        for x in 1..map.get_width() {
            for y in 1..map.get_height() {
                let x = x as u16;
                let y = y as u16;

                if (map.is_accessible_x_y(&x, &y)) {
                    counter_accessible += 1;
                } else {
                    counter_inaccessible += 1;
                }
            }
        }
    }

    println!("Total accessible cells: {}", counter_accessible);
    println!("Total inaccessible cells: {}", counter_inaccessible);
}

fn print_levelup(levels: &Vec<levelexp::Level>) {
	for b in 0..levels.len() {
		let ref current_level = levels[b];

		println!("Level: {}, EXP: {}", current_level.level, current_level.experience);
	}
}

fn print_levelup_hash(levels: &HashMap<u8, i32>) {
	for (level, exp) in levels {
		println!("Level: {}, EXP: {}", level, exp);
	}
}*/<commit_msg>Simplify main command line parser file<commit_after>#![recursion_limit="128"]

use std::io;
use std::io::*;
use std::io::prelude::*;
use std::fs::File;
use std::fs;
use std::process::Command;
use std::collections::HashMap;
use std::str;

use std::io::Cursor;
use std::env;

#[macro_use]
extern crate nom;
extern crate clap;
extern crate serde_json;
extern crate byteorder;

#[macro_use]
extern crate serde_derive;

use clap::{Arg, App, SubCommand, ArgMatches};

#[macro_use]
mod datfiles;
mod levelexp;
mod itemtype;
mod magictype;

fn get_app_usage<'a>() -> ArgMatches<'a> {
    App::new("CO V5165 Toolkit")
        .version("0.3.0")
        .author("Tarouka <tarouka@openmailbox.org>")

        .subcommand(SubCommand::with_name("decrypt_dat")
            .about("Decrypts a standard CO dat file (itemtype.dat, Monster.dat or MagicType.dat).")
            .arg(Arg::with_name("SRC_FILENAME").help("Source filename").required(true))
            .arg(Arg::with_name("DST_FILENAME").help("Destination filename").required(true))
        )

        .subcommand(SubCommand::with_name("encrypt_dat")
            .about("Encrypts a standard CO dat file (itemtype.dat, Monster.dat or MagicType.dat).")
            .arg(Arg::with_name("SRC_FILENAME").help("Source filename").required(true))
            .arg(Arg::with_name("DST_FILENAME").help("Destination filename").required(true))
        )

        .subcommand(SubCommand::with_name("itemtype")
            .about("Encodes or decodes an itemtype file to a parseable format.")

            .subcommand(SubCommand::with_name("decode")
                .about("Decodes an itemtype.dat file to a more workable format.")

                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes JSON by default"))
                .arg(Arg::with_name("decrypt").long("decrypt").short("d").help("The file will be decrypted before processing"))
                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
            )

            .subcommand(SubCommand::with_name("encode")
                .about("Encodes back an itemtype.dat decoded format.")

                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes the format from the extension by default"))
                .arg(Arg::with_name("encrypt").long("encrypt").short("e").help("The file will be encrypted"))
            )
        )

        .subcommand(SubCommand::with_name("magictype")
            .about("Encodes or decodes an magictype file to a parseable format.")

            .subcommand(SubCommand::with_name("decode")
                .about("Decodes an magictype.dat file to a more workable format.")

                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes JSON by default"))
                .arg(Arg::with_name("decrypt").long("decrypt").short("d").help("The file will be decrypted before processing"))
                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
            )

            .subcommand(SubCommand::with_name("encode")
                .about("Encodes back an magictype.dat decoded format.")

                .arg(Arg::with_name("FROM_FILE").help("Source filename").required(true))
                .arg(Arg::with_name("TO_FILE").help("Destination filename").required(true))
                .arg(Arg::with_name("output-format").long("output-format").short("o").takes_value(true).possible_values(&["json"]).help("Assumes the format from the extension by default"))
                .arg(Arg::with_name("encrypt").long("encrypt").short("e").help("The file will be encrypted"))
            )
        )

        .get_matches()

}

fn main() {
    let matches = get_app_usage();

    if let Some(matches) = matches.subcommand_matches("decrypt_dat") {
        commands::exec_decrypt_dat(&matches);
    }

    else if let Some(matches) = matches.subcommand_matches("encrypt_dat") {
        commands::exec_encrypt_dat(&matches);
    }

    else if let Some(matches) = matches.subcommand_matches("itemtype") {
        if let Some(matches) = matches.subcommand_matches("decode") {
            commands::exec_itemtype_decode(&matches);
        }

        if let Some(matches) = matches.subcommand_matches("encode") {
            commands::exec_itemtype_encode(&matches);
        }
    }

    else if let Some(matches) = matches.subcommand_matches("magictype") {
        if let Some(matches) = matches.subcommand_matches("decode") {
            commands::exec_magictype_decode(&matches);
        }

        if let Some(matches) = matches.subcommand_matches("encode") {
            commands::exec_magictype_encode(&matches);
        }
    }

    else {
        println!("{}", matches.usage());
    }
}

pub fn decrypt_cofac_dat(source: &str) -> Vec<u8> {
    let cofac_key = datfiles::generate_cofac_key();
    println!("Generated COFAC key successfully!");

    let bytes_read = read_all_bytes(source);
    println!("File successfully read.");

    let bytes_dec = datfiles::decrypt_bytes(&bytes_read, &cofac_key);
    println!("Decryption complete.");

    bytes_dec
}

pub fn encrypt_cofac_bytes(source_bytes: Vec<u8>) -> Vec<u8> {
    let cofac_key = datfiles::generate_cofac_key();
    println!("Generated COFAC key successfully!");

    let bytes_enc = datfiles::encrypt_bytes(&source_bytes, &cofac_key);
    println!("Encryption complete.");

    bytes_enc
}

pub fn encrypt_cofac_dat(source: &str) -> Vec<u8> {
    let cofac_key = datfiles::generate_cofac_key();
    println!("Generated COFAC key successfully!");

    let bytes_read = read_all_bytes(source);
    println!("File successfully read.");

    let bytes_enc = datfiles::encrypt_bytes(&bytes_read, &cofac_key);
    println!("Encryption complete.");

    bytes_enc
}

pub fn read_all_bytes(filename: &str) -> Vec<u8> {
    let mut f = File::open(filename).unwrap();
    let mut buffer = Vec::new();

    let bytes_read = f.read_to_end(&mut buffer).unwrap();

    buffer
}

pub fn write_all_bytes(filename: &str, bytes: Vec<u8>) {
    let mut f = File::create(filename).unwrap();

    f.write_all(&bytes);
}

mod commands {
    use super::*;
    use datfiles::parser::ParserSerializable;

    struct DecoderArgs<'a> {
        src_filename: &'a str,
        dst_filename: &'a str,
        format: &'a str,
        decrypt: bool
    }

    struct EncoderArgs<'a> {
        src_filename: &'a str,
        dst_filename: &'a str,
        format: &'a str,
        encrypt: bool
    }

    fn get_decoder_args<'a>(matches: &'a ArgMatches) -> DecoderArgs<'a> {
        DecoderArgs {
            src_filename: matches.value_of("FROM_FILE").unwrap(),
            dst_filename: matches.value_of("TO_FILE").unwrap(),
            format: matches.value_of("format").unwrap_or("json"),
            decrypt: matches.is_present("decrypt")
        }
    }

    fn get_encoder_args<'a>(matches: &'a ArgMatches) -> EncoderArgs<'a> {
        EncoderArgs {
            src_filename: matches.value_of("FROM_FILE").unwrap(),
            dst_filename: matches.value_of("TO_FILE").unwrap(),
            format: matches.value_of("format").unwrap_or("json"),
            encrypt: matches.is_present("encrypt")
        }
    }

    pub fn exec_decrypt_dat<'a>(matches: &'a ArgMatches) {
        let src_filename = matches.value_of("SRC_FILENAME").unwrap();
        let dst_filename = matches.value_of("DST_FILENAME").unwrap();

        let bytes_dec = decrypt_cofac_dat(src_filename);

        write_all_bytes(dst_filename, bytes_dec);
        println!("Wrote decrypted file to {} successfully.", dst_filename);
    }

    pub fn exec_encrypt_dat<'a>(matches: &'a ArgMatches) {
        let src_filename = matches.value_of("SRC_FILENAME").unwrap();
        let dst_filename = matches.value_of("DST_FILENAME").unwrap();

        let bytes_enc = encrypt_cofac_dat(src_filename);

        write_all_bytes(dst_filename, bytes_enc);
        println!("Wrote encrypted file to {} successfully.", dst_filename);
    }

    pub fn exec_itemtype_decode<'a>(matches: &'a ArgMatches) {
        let args = get_decoder_args(matches);

        let src_bytes = if args.decrypt { decrypt_cofac_dat(args.src_filename) } else { read_all_bytes(&args.src_filename) };
        let parsed_file = itemtype::parser::parse_item_type(&src_bytes);

        let mut bytes_to_write: Vec<u8> = Vec::new();

        match parsed_file {
            Some(item_type) => {
                if args.format == "json" {
                    bytes_to_write = itemtype::encoder::decode_item_type_to_json(&item_type);
                }
            },

            None => {
                panic!("An error occured while parsing the file.");
            }
        }

        write_all_bytes(&args.dst_filename, bytes_to_write);
    }

    pub fn exec_itemtype_encode<'a>(matches: &'a ArgMatches) {
        let args = get_encoder_args(matches);

        let src_bytes = read_all_bytes(&args.src_filename);
        let decoded_file = itemtype::encoder::encode_item_type_from_json(src_bytes);

        let mut encoded_bytes: Vec<u8> = Vec::new();

        if args.format == "json" {
            encoded_bytes = decoded_file.serialize_to_string().into_bytes();
        } else {
            panic!("Unsupported format");
        }

        let mut bytes_to_write = if args.encrypt { encrypt_cofac_bytes(encoded_bytes) } else { encoded_bytes };

        write_all_bytes(&args.dst_filename, bytes_to_write);
    }

    pub fn exec_magictype_decode<'a>(matches: &'a ArgMatches) {
        let args = get_decoder_args(matches);

        let src_bytes = if args.decrypt { decrypt_cofac_dat(args.src_filename) } else { read_all_bytes(&args.src_filename) };
        let parsed_file = magictype::parser::parse_magic_type(&src_bytes);

        let mut bytes_to_write: Vec<u8> = Vec::new();

        match parsed_file {
            Some(magic_type) => {
                if args.format == "json" {
                    bytes_to_write = magictype::encoder::decode_magic_type_to_json(&magic_type);
                }
            },

            None => {
                panic!("An error occured while parsing the file.");
            }
        }

        write_all_bytes(&args.dst_filename, bytes_to_write);
    }

    pub fn exec_magictype_encode<'a>(matches: &'a ArgMatches) {
        let args = get_encoder_args(matches);

        let src_bytes = read_all_bytes(&args.src_filename);
        let decoded_file = magictype::encoder::encode_magic_type_from_json(src_bytes);

        let mut encoded_bytes: Vec<u8> = Vec::new();

        if args.format == "json" {
            encoded_bytes = decoded_file.serialize_to_string().into_bytes();
        } else {
            panic!("Unsupported format");
        }

        let mut bytes_to_write = if args.encrypt { encrypt_cofac_bytes(encoded_bytes) } else { encoded_bytes };

        write_all_bytes(&args.dst_filename, bytes_to_write);
    }
}

/*fn read_all_maps() {
    let maps_folder = "";
    let maps_folder_content = fs::read_dir(maps_folder).unwrap();
    let mut maps_store: Vec<u8>;
    let mut maps: Vec<maps::Map> = Vec::new();

    for map_filename in maps_folder_content {
        let map_filename_unwrapped = map_filename.unwrap().path();
        let map_filename_str = map_filename_unwrapped.to_str();
        let mut map_buff: Vec<u8> = Vec::new();

        match map_filename_str {
            Some(map_filename_actual) => {
                println!("Name: {}", map_filename_actual);
                let buff = maps::read_map_bytes(map_filename_actual);

                match maps::parse_map(&buff) {
                    Some(map) => {
                        println!(" - Map Width: {}", map.get_width());
                        println!(" - Map Height: {}", map.get_height());

                        maps.push(map);
                    },
                    None => {
                        println!("Failed to read map");
                    }
                }
            },
            None => {
                println!("File not found");
            }
        }
    }

    let mut counter_accessible: u64 = 0;
    let mut counter_inaccessible: u64 = 0;

    for map in maps {
        for x in 1..map.get_width() {
            for y in 1..map.get_height() {
                let x = x as u16;
                let y = y as u16;

                if (map.is_accessible_x_y(&x, &y)) {
                    counter_accessible += 1;
                } else {
                    counter_inaccessible += 1;
                }
            }
        }
    }

    println!("Total accessible cells: {}", counter_accessible);
    println!("Total inaccessible cells: {}", counter_inaccessible);
}

fn print_levelup(levels: &Vec<levelexp::Level>) {
	for b in 0..levels.len() {
		let ref current_level = levels[b];

		println!("Level: {}, EXP: {}", current_level.level, current_level.experience);
	}
}

fn print_levelup_hash(levels: &HashMap<u8, i32>) {
	for (level, exp) in levels {
		println!("Level: {}, EXP: {}", level, exp);
	}
}*/<|endoftext|>


<commit_before>#[macro_use]
extern crate rocket;

#[macro_use]
extern crate rocket_contrib;

mod airport_data;
mod path;
mod server_route;

use anyhow::Result;
use anyhow::{anyhow, Context};
use rocket::config::{Config, Environment};
use rocket_contrib::serve::StaticFiles;

#[rocket::main]
async fn main() -> Result<()> {
    if let Err(err) = airport_data::ensure_updated() {
        return Err(anyhow!("airport data update failed: {}", err));
    }

    println!("loading airport data..");

    let airports = match airport_data::Airport::load_all() {
        Ok(airports) => airports,
        Err(err) => return Err(anyhow!("error loading airport data: {}", err)),
    };

    println!("finished loading airport data..");

    let config = Config::build(Environment::active().unwrap())
        .workers(1)
        .finalize()
        .context("failed to build Rocket config")?;

    rocket::custom(config)
        .manage(airports)
        .mount("/", StaticFiles::from("frontend/public/"))
        .mount("/api", routes![server_route::search_routes::search_routes])
        .launch()
        .await
        .with_context(|| anyhow!("failed to initialize Rocket"))
}
<commit_msg>backend: Don't unwrap Environment::active() errors<commit_after>#[macro_use]
extern crate rocket;

#[macro_use]
extern crate rocket_contrib;

mod airport_data;
mod path;
mod server_route;

use anyhow::Result;
use anyhow::{anyhow, Context};
use rocket::config::{Config, Environment};
use rocket_contrib::serve::StaticFiles;

#[rocket::main]
async fn main() -> Result<()> {
    if let Err(err) = airport_data::ensure_updated() {
        return Err(anyhow!("airport data update failed: {}", err));
    }

    println!("loading airport data..");

    let airports = match airport_data::Airport::load_all() {
        Ok(airports) => airports,
        Err(err) => return Err(anyhow!("error loading airport data: {}", err)),
    };

    println!("finished loading airport data..");

    let config = {
        let env = Environment::active().context("failed to get Rocket config")?;

        Config::build(env)
            .workers(1)
            .finalize()
            .context("failed to build Rocket config")?
    };

    rocket::custom(config)
        .manage(airports)
        .mount("/", StaticFiles::from("frontend/public/"))
        .mount("/api", routes![server_route::search_routes::search_routes])
        .launch()
        .await
        .with_context(|| anyhow!("failed to initialize Rocket"))
}
<|endoftext|>


<commit_before>#![feature(unboxed_closures, fn_traits)]
// MSPC == 'multiple sender, single receiver'
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

type Payload = i32;

struct Message {
    payload: Payload,
    sender: Sender<Payload>,
}

struct Actor {
    inbox: Receiver<Message>
}

impl Actor {
    fn new(inbox: Receiver<Message>) -> Actor {
        Actor{inbox: inbox}
    }
}

impl FnOnce<()> for Actor {
    type Output = ();
    extern "rust-call" fn call_once(self, _: ()) -> () {
        // Forever...
        loop {
            // See if we have messages!
            match self.inbox.recv() {
                // If we're given a 'special' -1 value, exit.
                Ok(Message{payload, sender: _}) if payload == -1 => {
                    println!("[Actor] Exiting!");
                    break;
                },
                // Otherwise, print and respond to the message!
                Ok(Message{payload, sender}) => {
                    println!("[Actor] Got: {:?}", payload);
                    sender.send(payload + 1).unwrap();
                },
                // Exit on error
                Err(e) => {
                    println!("[Actor] Error: {:?}", e);
                    break;
                },
            }
        }
    }
}

struct ActorRef {
    outbox: Sender<Message>
}

impl ActorRef {
    fn new(outbox: Sender<Message>) -> ActorRef {
        ActorRef{outbox: outbox}
    }
}

fn main() {
    // Actor Mailbox
    let (outbox, inbox): (Sender<Message>, Receiver<Message>) = mpsc::channel();

    let actor = Actor::new(inbox);
    let r = ActorRef::new(outbox);

    // Create a new thread
    let handle = thread::Builder::new()
        .name("actor".into())
        .spawn(actor)
        .unwrap();

    // Communication channel with actor
    let (sender, receiver): (Sender<Payload>, Receiver<Payload>) = mpsc::channel();
    r.outbox.send(Message{payload: 0, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send another number!
    r.outbox.send(Message{payload: num + 1, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send exit code
    r.outbox.send(Message{payload: -1, sender: sender.clone()}).unwrap();

    // Wait for thread to exit
    let res = handle.join().unwrap();
    println!("[Main] Res: {:?}", res);
}
<commit_msg>Actor Trait!<commit_after>#![feature(unboxed_closures, fn_traits)]
// MSPC == 'multiple sender, single receiver'
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::thread;

type Payload = i32;

struct Message {
    payload: Payload,
    sender: Sender<Payload>,
}

trait Actor {
    fn run(&self) -> ();
}

struct ActorHarness<T: Actor> {
    inbox: Receiver<Message>,
    actor: T
}

impl<T: Actor> ActorHarness<T> {
    fn new(inbox: Receiver<Message>, actor: T) -> ActorHarness<T> {
        ActorHarness{inbox: inbox, actor: actor}
    }
}

impl<T: Actor> FnOnce<()> for ActorHarness<T> {
    type Output = ();
    extern "rust-call" fn call_once(self, _: ()) -> () {
        // Forever...
        loop {

            self.actor.run();

            // See if we have messages!
            match self.inbox.recv() {
                // If we're given a 'special' -1 value, exit.
                Ok(Message{payload, sender: _}) if payload == -1 => {
                    println!("[Actor] Exiting!");
                    break;
                },
                // Otherwise, print and respond to the message!
                Ok(Message{payload, sender}) => {
                    println!("[Actor] Got: {:?}", payload);
                    sender.send(payload + 1).unwrap();
                },
                // Exit on error
                Err(e) => {
                    println!("[Actor] Error: {:?}", e);
                    break;
                },
            }
        }
    }
}

struct ActorRef {
    outbox: Sender<Message>
}

impl ActorRef {
    fn new(outbox: Sender<Message>) -> ActorRef {
        ActorRef{outbox: outbox}
    }
}

struct ActorImpl {
}

impl ActorImpl {
    fn new() -> ActorImpl {
        ActorImpl {}
    }
}

impl Actor for ActorImpl {
    fn run(&self) -> () {
        println!("Hello!");
    }
}

fn main() {
    // Actor Mailbox
    let (outbox, inbox): (Sender<Message>, Receiver<Message>) = mpsc::channel();

    let actor = ActorImpl::new();
    let harness = ActorHarness::new(inbox, actor);
    let r = ActorRef::new(outbox);

    // Create a new thread
    let handle = thread::Builder::new()
        .name("actor".into())
        .spawn(harness)
        .unwrap();

    // Communication channel with actor
    let (sender, receiver): (Sender<Payload>, Receiver<Payload>) = mpsc::channel();
    r.outbox.send(Message{payload: 0, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send another number!
    r.outbox.send(Message{payload: num + 1, sender: sender.clone()}).unwrap();
    let num = receiver.recv().unwrap();
    println!("[Main] Got: {:?}", num);

    // Send exit code
    r.outbox.send(Message{payload: -1, sender: sender.clone()}).unwrap();

    // Wait for thread to exit
    let res = handle.join().unwrap();
    println!("[Main] Res: {:?}", res);
}
<|endoftext|>


<commit_before>extern crate rustylifx;
extern crate clap;
extern crate termcolor;

use rustylifx::{colour, messages, network, response};
use rustylifx::colour::HSB;
use rustylifx::network::Device;

use std::io::Write;
use std::process;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

fn exit_usage(s: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);
    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(e) => println!("Failed setting terminal output colour: {}", e),
    };

    let s_out = format!("\n\n{}\nUsage: `lifxcmd --help`", s);
    if writeln!(&mut stdout,"{}", s_out).is_err() {
        println!("{}", s_out);
    };

    process::exit(1);
}

fn exit_error(s: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);
    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(e) => println!("Failed setting terminal output colour: {}", e),
    };

    let s_out = format!("\n\n{}", s);
    if writeln!(&mut stdout,"{}", s_out).is_err() {
        println!("{}", s_out);
    };

    process::exit(1);
}

fn main() {
    // Configure flags.
    let matches = App::new("Lifx Command")
        .version("0.1.1")
        .author("Russell Mackenzie")
        .about("Control Lifx devices from the command line.")
        .arg(Arg::with_name("address")
            .short("a")
            .long("address")
            .value_name("HOST ADDRESS")
            .help("Specifies the address of the target device")
            .takes_value(true))
        .arg(Arg::with_name("power")
            .short("p")
            .long("power")
            .value_name("POWER LEVEL")
            .help("Changes the power level on/off")
            .takes_value(true))
        .arg(Arg::with_name("colour")
            .short("c")
            .long("colour")
            .value_name("COLOUR NAME")
            .help("Changes the colour")
            .takes_value(true))
        .arg(Arg::with_name("flash")
            .short("f")
            .long("flash")
            .value_name("FLASH COLOUR NAME")
            .help("Specifies the name of the colour to flash")
            .takes_value(true))
        .arg(Arg::with_name("interval")
            .short("i")
            .long("interval")
            .value_name("FLASH INTERVAL")
            .help("The length of the flash")
            .takes_value(true))
        .arg(Arg::with_name("duration")
            .short("d")
            .long("duration")
            .value_name("TRANSITION DURATION")
            .help("The duration of the colour transition")
            .takes_value(true))
        .arg(Arg::with_name("report")
            .short("r")
            .long("report")
            .value_name("DISPLAY CURRENT STATE")
            .help("Display the current state of the device")
            .takes_value(false))
        .arg(Arg::with_name("hue")
            .short("h")
            .long("hue")
            .value_name("HUE")
            .help("Set the hue of the device")
            .takes_value(true))
        .arg(Arg::with_name("saturation")
            .short("s")
            .long("saturation")
            .value_name("SATURATION")
            .help("Set the saturation of the device")
            .takes_value(true))
        .arg(Arg::with_name("brightness")
            .short("b")
            .long("brightness")
            .value_name("BRIGHTNESS")
            .help("Set the brightness of the device")
            .takes_value(true))
        .get_matches();

    // Find the device, by flag, else broadcast.
    let device = match matches.value_of("address").unwrap_or("") {
        "" => {
            // Locate device.
            match messages::get_service() {
                Ok(v)   => v,
                Err(e)  => {
                    exit_error(format!("Failed finding device: {}",e));
                    return
                },
            }
        },
        ip => {
            // Set device.
            const PORT: u16 = 56700;
            network::Device {
                socket_addr: format!("{}:{}", ip, PORT).parse().expect("invalid socket address"),
                response: None,
            }
        },
    };

    // Check if state display was specified.
    if matches.is_present("report") {
        let device = get_device_state(device);
        display(&device);
        return
    }

    // Set the power level on/off.
    if let Some(v) = matches.value_of("power") {
        let res = match v {
            "on"  => messages::set_device_on(&device),
            "off" => messages::set_device_off(&device),
            _ => {
                exit_usage("Power state is invalid, should be on or off.".to_string());
                return
            },
        };

        if res.is_err() {
            exit_error(format!("Failed setting device power state: {:?}", res.err()));
            return
        }
    };

    // Check if transition duration was specified.
    let duration = match matches.value_of("duration") {
        Some(v) => {
            match v.parse::<u32>() {
                Ok(n) => n,
                Err(e) => {
                    exit_usage(format!("Duration is not a valid number: {}", e));
                    return
                },
            }
        }
        None => 0,
    };

    // Set the colour by name if flag exists.
    if let Some(v) = matches.value_of("colour") {
        let _ = messages::set_device_state(&device, &colour::get_colour(v), 1000, duration);
        return
    }

    // Set the colour by HSB if specified.
    // HSB: 360º, 100%, 100%
    let mut hue = match matches.value_of("hue") {
        Some(v) => {
            match v.parse::<i16>() {
                Ok(n) => {
                    if n >= 0 && n <= 360 {
                        n
                    } else {
                        exit_usage("Hue is outside the valid range, should be 0 - 360 (degrees)".to_string());
                        return
                    }
                }
                Err(e) => {
                    exit_usage(format!("Hue is not a valid number: {}", e));
                    return
                },
            }
        }
        None => -1,
    };

    let mut saturation = match matches.value_of("saturation") {
        Some(v) => {
            match v.parse::<i16>() {
                Ok(n) => {
                    if n >= 0 && n <= 100 {
                        n
                    } else {
                        exit_usage("Saturation is outside the valid range, should be 0 - 100 (percent)".to_string());
                        return
                    }
                }
                Err(e) => {
                    exit_usage(format!("Saturation is not a valid number: {}", e));
                    return
                },
            }
        }
        None => -1,
    };

    let mut brightness = match matches.value_of("brightness") {
        Some(v) => {
            match v.parse::<i16>() {
                Ok(n) => {
                    if n >= 0 && n <= 100 {
                        n
                    } else {
                        exit_usage("Brightness is outside the valid range, should be 0 - 100 (percent)".to_string());
                        return
                    }
                }
                Err(e) => {
                    exit_usage(format!("Brightness is not a valid number: {}", e));
                    return
                },
            }
        }
        None => -1,
    };

    if hue >= 0 || saturation >= 0 || brightness >= 0 {
        if hue < 0 {
            hue = 360;
        }

        if saturation < 0 {
            saturation = 100;
        }

        if brightness < 0 {
            brightness = 100;
        }

        let _ = messages::set_device_state(&device,
                                           &colour::HSB {
                                               hue: hue as u16,
                                               saturation: saturation as u8,
                                               brightness: brightness as u8,
                                           },
                                           1000,
                                           duration);
        return
    }

    // Check if the flash interval was specified.
    let interval = match matches.value_of("interval") {
        Some(v) => {
            match v.parse::<u64>() {
                Ok(n) => n,
                Err(e) => {
                    exit_usage(format!("Interval is not a valid number: {}", e));
                    return
                },
            }
        }
        None => 1000,
    };

    // Flash if flag exists.
    if let Some(v) = matches.value_of("flash") {
        flash(device, colour::get_colour(v), interval);
        return
    };

    // TODO: ponder fade
    // let fade_len: u32 = 3000;
    // fade(&device, colour::get_colour("crimson"), fade_len);
    // thread::sleep(Duration::from_millis((fade_len + 1) as u64));
    // Fade device back to initial state.
    // fade(&device, initial_state.unwrap(), 3000);
}

fn get_device_state(device: Device) -> Device {
    // TODO: sort out this hacky sleep.
    thread::sleep(Duration::from_millis(1000));
    messages::get_device_state(device).unwrap()
}

fn flash(device: Device, flash_colour: HSB, duration_ms: u64) {
    let device = get_device_state(device);

    // Extract current HSVK from device state data.
    let resp = match device.response {
        Some(ref v) => v,
        None => panic!("no response"),
    };

    let payload = match resp.payload {
        response::Payload::State(ref v) => Some(v),
        _ => None,
    };

    let initial_state = match payload {
        Some(v) => {
            let h = colour::hue_word_to_degrees(v.hsbk.hue);
            let s = colour::saturation_word_to_percent(v.hsbk.saturation as u16);
            let b = colour::brightness_word_to_percent(v.hsbk.brightness as u16);
            Some(colour::HSB::new(h, s, b))
        }
        None => None,
    };

    if let Some(v) = initial_state {
        // Change device state temporarily.
        let _ = messages::set_device_state(&device, &flash_colour, 2500, 0);
        thread::sleep(Duration::from_millis(duration_ms));

        // Return device to initial state.
        let _ = messages::set_device_state(&device, &v, 2500, 0);
    }
}

fn display(device: &Device) {
    let resp = match device.response {
        Some(ref v) => v,
        None => {
            println!("No response from device.");
            return;
        }
    };

    println!("\nDevice State:");
    println!("Source: {:?}", resp.source);
    println!("Mac addr: {:?}", resp.mac_address);
    println!("Firmware: {:?}", resp.firmware);

    println!("\nResponse:");
    println!("Size: {}", resp.size);

    // packed byte
    println!("Sequence num: {:?}", resp.sequence_number);
    println!("Reserved_1 (timestamp?): {:?}", resp.reserved_1);
    println!("Message type: {:?}", resp.message_type);
    println!("Reserved_2: {:?}", resp.reserved_2);

    match resp.payload {
        response::Payload::StateService(ref v) => {
            println!("Service: {:?}", v.service);
            println!("Port: {:?}", v.port);
            println!("Unknown: {:?}", v.unknown);
        }
        response::Payload::State(ref v) => {
            println!("Body: {:?}", v.body);
            println!("HSBK: {:?}", v.hsbk);
            println!("current hue: {:?}", v.hsbk.hue);
            println!("current hue degrees: {:?}º",
                     colour::hue_word_to_degrees(v.hsbk.hue));
            println!("current sat: {:?}", v.hsbk.saturation);
            println!("current sat percent: {:?}%",
                     colour::saturation_word_to_percent(v.hsbk.saturation as u16));
            println!("current bri: {:?}", v.hsbk.brightness);
            println!("current bri percent: {:?}%",
                     colour::brightness_word_to_percent(v.hsbk.brightness as u16));
            println!("current kel: {:?}", v.hsbk.kelvin);
        }
        _ => (),
    };

    println!("==========");
}
<commit_msg>Add initial result tui.<commit_after>extern crate rustylifx;
extern crate clap;
extern crate termcolor;

use rustylifx::{colour, messages, network, response};
use rustylifx::colour::HSB;
use rustylifx::network::Device;

use std::io::Write;
use std::process;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

fn print_line_info_prefix(icon: &str, status: &str, message: &str, colour_primary: Color, colour_secondary: Color) {
    // Display icon.
    print_string(icon, colour_primary, false);

    // Display status left brace.
    let left_brace = " [";
    print_string(left_brace, colour_secondary, false);

    // Display status word.
    print_string(status, colour_primary, false);

    // Display status right brace.
    let right_brace = "]\t";
    print_string(right_brace, colour_secondary, false);

    // Display message.
    print_string(message, colour_secondary, false);
}

fn print_string(s: &str, colour: Color, bold: bool) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    let mut colour_spec = ColorSpec::new();
    colour_spec.set_fg(Some(colour));
    colour_spec.set_bold(bold);

    match stdout.set_color(&colour_spec) {
        Ok(_) => (),
        Err(e) => println!("Failed setting terminal output colour: {}", e),
    };
    let s_out = format!("{}", s);
    if write!(&mut stdout,"{}", s_out).is_err() {
        print!("{}", s_out);
    };
}

fn print_response_header() {
    println!("\n");
    print_string("== ", Color::Cyan, false);
    print_string("Result", Color::White, true);
    print_string(" ===========================================================================", Color::Cyan, false);
    println!("\n");
}

fn exit_usage(s: String) {
    print_response_header();

    // Display error.
    print_line_info_prefix("!", "invalid", &s, Color::Yellow, Color::White);

    // Display usage.
    println!("");
    let s_out = format!("lifxcmd --help");
    print_line_info_prefix("→", "usage", &s_out, Color::Cyan, Color::White);
    println!("\n");

    process::exit(1);
}

fn exit_error(s: String) {
    print_response_header();

    print_line_info_prefix("✘", "error", &s, Color::Red, Color::White);
    println!("\n");

    process::exit(1);
}

fn exit_done() {
    print_response_header();

    print_line_info_prefix("∗", "Done", "", Color::Green, Color::White);
    println!("\n");

    process::exit(0);
}

fn main() {
    // Configure flags.
    let matches = App::new("Lifx Command")
        .version("0.1.1")
        .author("Russell Mackenzie")
        .about("Control Lifx devices from the command line.")
        .arg(Arg::with_name("address")
            .short("a")
            .long("address")
            .value_name("HOST ADDRESS")
            .help("Specifies the address of the target device")
            .takes_value(true))
        .arg(Arg::with_name("power")
            .short("p")
            .long("power")
            .value_name("POWER LEVEL")
            .help("Changes the power level on/off")
            .takes_value(true))
        .arg(Arg::with_name("colour")
            .short("c")
            .long("colour")
            .value_name("COLOUR NAME")
            .help("Changes the colour")
            .takes_value(true))
        .arg(Arg::with_name("flash")
            .short("f")
            .long("flash")
            .value_name("FLASH COLOUR NAME")
            .help("Specifies the name of the colour to flash")
            .takes_value(true))
        .arg(Arg::with_name("interval")
            .short("i")
            .long("interval")
            .value_name("FLASH INTERVAL")
            .help("The length of the flash")
            .takes_value(true))
        .arg(Arg::with_name("duration")
            .short("d")
            .long("duration")
            .value_name("TRANSITION DURATION")
            .help("The duration of the colour transition")
            .takes_value(true))
        .arg(Arg::with_name("report")
            .short("r")
            .long("report")
            .value_name("DISPLAY CURRENT STATE")
            .help("Display the current state of the device")
            .takes_value(false))
        .arg(Arg::with_name("hue")
            .short("h")
            .long("hue")
            .value_name("HUE")
            .help("Set the hue of the device")
            .takes_value(true))
        .arg(Arg::with_name("saturation")
            .short("s")
            .long("saturation")
            .value_name("SATURATION")
            .help("Set the saturation of the device")
            .takes_value(true))
        .arg(Arg::with_name("brightness")
            .short("b")
            .long("brightness")
            .value_name("BRIGHTNESS")
            .help("Set the brightness of the device")
            .takes_value(true))
        .get_matches();

    // Find the device, by flag, else broadcast.
    let device = match matches.value_of("address").unwrap_or("") {
        "" => {
            // Locate device.
            match messages::get_service() {
                Ok(v)   => v,
                Err(e)  => {
                    exit_error(format!("Failed finding device: {}",e));
                    return
                },
            }
        },
        ip => {
            // Set device.
            const PORT: u16 = 56700;
            network::Device {
                socket_addr: format!("{}:{}", ip, PORT).parse().expect("invalid socket address"),
                response: None,
            }
        },
    };

    // Check if state display was specified.
    if matches.is_present("report") {
        let device = get_device_state(device);
        display(&device);
        return
    }

    // Set the power level on/off.
    if let Some(v) = matches.value_of("power") {
        let res = match v {
            "on"  => messages::set_device_on(&device),
            "off" => messages::set_device_off(&device),
            _ => {
                exit_usage("Power state is invalid, should be on or off.".to_string());
                return
            },
        };

        if res.is_err() {
            exit_error(format!("Failed setting device power state: {:?}", res.err()));
            return
        }
    };

    // Check if transition duration was specified.
    let duration = match matches.value_of("duration") {
        Some(v) => {
            match v.parse::<u32>() {
                Ok(n) => n,
                Err(e) => {
                    exit_usage(format!("Duration is not a valid number: {}", e));
                    return
                },
            }
        }
        None => 0,
    };

    // Set the colour by name if flag exists.
    if let Some(v) = matches.value_of("colour") {
        let _ = messages::set_device_state(&device, &colour::get_colour(v), 1000, duration);
        return
    }

    // Set the colour by HSB if specified.
    // HSB: 360º, 100%, 100%
    let mut hue = match matches.value_of("hue") {
        Some(v) => {
            match v.parse::<i16>() {
                Ok(n) => {
                    if n >= 0 && n <= 360 {
                        n
                    } else {
                        exit_usage("Hue is outside the valid range, should be 0 - 360 (degrees)".to_string());
                        return
                    }
                }
                Err(e) => {
                    exit_usage(format!("Hue is not a valid number: {}", e));
                    return
                },
            }
        }
        None => -1,
    };

    let mut saturation = match matches.value_of("saturation") {
        Some(v) => {
            match v.parse::<i16>() {
                Ok(n) => {
                    if n >= 0 && n <= 100 {
                        n
                    } else {
                        exit_usage("Saturation is outside the valid range, should be 0 - 100 (percent)".to_string());
                        return
                    }
                }
                Err(e) => {
                    exit_usage(format!("Saturation is not a valid number: {}", e));
                    return
                },
            }
        }
        None => -1,
    };

    let mut brightness = match matches.value_of("brightness") {
        Some(v) => {
            match v.parse::<i16>() {
                Ok(n) => {
                    if n >= 0 && n <= 100 {
                        n
                    } else {
                        exit_usage("Brightness is outside the valid range, should be 0 - 100 (percent)".to_string());
                        return
                    }
                }
                Err(e) => {
                    exit_usage(format!("Brightness is not a valid number: {}", e));
                    return
                },
            }
        }
        None => -1,
    };

    if hue >= 0 || saturation >= 0 || brightness >= 0 {
        if hue < 0 {
            hue = 360;
        }

        if saturation < 0 {
            saturation = 100;
        }

        if brightness < 0 {
            brightness = 100;
        }

        let _ = messages::set_device_state(&device,
                                           &colour::HSB {
                                               hue: hue as u16,
                                               saturation: saturation as u8,
                                               brightness: brightness as u8,
                                           },
                                           1000,
                                           duration);
        return
    }

    // Check if the flash interval was specified.
    let interval = match matches.value_of("interval") {
        Some(v) => {
            match v.parse::<u64>() {
                Ok(n) => n,
                Err(e) => {
                    exit_usage(format!("Interval is not a valid number: {}", e));
                    return
                },
            }
        }
        None => 1000,
    };

    // Flash if flag exists.
    if let Some(v) = matches.value_of("flash") {
        flash(device, colour::get_colour(v), interval);
        return
    };

    // TODO: ponder fade
    // let fade_len: u32 = 3000;
    // fade(&device, colour::get_colour("crimson"), fade_len);
    // thread::sleep(Duration::from_millis((fade_len + 1) as u64));
    // Fade device back to initial state.
    // fade(&device, initial_state.unwrap(), 3000);

    exit_done();
}

fn get_device_state(device: Device) -> Device {
    // TODO: sort out this hacky sleep.
    thread::sleep(Duration::from_millis(1000));
    messages::get_device_state(device).unwrap()
}

fn flash(device: Device, flash_colour: HSB, duration_ms: u64) {
    let device = get_device_state(device);

    // Extract current HSVK from device state data.
    let resp = match device.response {
        Some(ref v) => v,
        None => panic!("no response"),
    };

    let payload = match resp.payload {
        response::Payload::State(ref v) => Some(v),
        _ => None,
    };

    let initial_state = match payload {
        Some(v) => {
            let h = colour::hue_word_to_degrees(v.hsbk.hue);
            let s = colour::saturation_word_to_percent(v.hsbk.saturation as u16);
            let b = colour::brightness_word_to_percent(v.hsbk.brightness as u16);
            Some(colour::HSB::new(h, s, b))
        }
        None => None,
    };

    if let Some(v) = initial_state {
        // Change device state temporarily.
        let _ = messages::set_device_state(&device, &flash_colour, 2500, 0);
        thread::sleep(Duration::from_millis(duration_ms));

        // Return device to initial state.
        let _ = messages::set_device_state(&device, &v, 2500, 0);
    }
}

fn display(device: &Device) {
    let resp = match device.response {
        Some(ref v) => v,
        None => {
            println!("No response from device.");
            return;
        }
    };

    println!("\nDevice State:");
    println!("Source: {:?}", resp.source);
    println!("Mac addr: {:?}", resp.mac_address);
    println!("Firmware: {:?}", resp.firmware);

    println!("\nResponse:");
    println!("Size: {}", resp.size);

    // packed byte
    println!("Sequence num: {:?}", resp.sequence_number);
    println!("Reserved_1 (timestamp?): {:?}", resp.reserved_1);
    println!("Message type: {:?}", resp.message_type);
    println!("Reserved_2: {:?}", resp.reserved_2);

    match resp.payload {
        response::Payload::StateService(ref v) => {
            println!("Service: {:?}", v.service);
            println!("Port: {:?}", v.port);
            println!("Unknown: {:?}", v.unknown);
        }
        response::Payload::State(ref v) => {
            println!("Body: {:?}", v.body);
            println!("HSBK: {:?}", v.hsbk);
            println!("current hue: {:?}", v.hsbk.hue);
            println!("current hue degrees: {:?}º",
                     colour::hue_word_to_degrees(v.hsbk.hue));
            println!("current sat: {:?}", v.hsbk.saturation);
            println!("current sat percent: {:?}%",
                     colour::saturation_word_to_percent(v.hsbk.saturation as u16));
            println!("current bri: {:?}", v.hsbk.brightness);
            println!("current bri percent: {:?}%",
                     colour::brightness_word_to_percent(v.hsbk.brightness as u16));
            println!("current kel: {:?}", v.hsbk.kelvin);
        }
        _ => (),
    };

    println!("==========");
}
<|endoftext|>


<commit_before>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?

extern crate serialize;

use std::collections::TreeMap;
use std::option::{None, Option, Some};
use serialize::json::ToJson;
use serialize::json;

/// Pos (alias for Positions)
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Pos(pub Vec<f64>);

impl ToJson for Pos {
    fn to_json(&self) -> json::Json {
        let &Pos(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Pos {
    fn clone(&self) -> Pos {
        let &Pos(ref nums) = self;
        Pos(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Pos,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Pos> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Pos>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Pos>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Pos>,
    pub holes: Option<Vec<Vec<Pos>>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Pos>> {
        match self.holes {
            None => vec![self.exterior.clone()],
            Some(ref holes) => {
                let mut coordinates = holes.clone();
                coordinates.insert(0, self.exterior.clone());
                coordinates
            }
        }
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Pos>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    EnumPoint(Point),
    EnumMultiPoint(MultiPoint),
    EnumLineString(LineString),
    EnumMultiLineString(MultiLineString),
    EnumPolygon(Polygon),
    EnumMultiPolygon(MultiPolygon),
    EnumGeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            EnumPoint(ref geom) => geom.to_json(),
            EnumMultiPoint(ref geom) => geom.to_json(),
            EnumLineString(ref geom) => geom.to_json(),
            EnumMultiLineString(ref geom) => geom.to_json(),
            EnumPolygon(ref geom) => geom.to_json(),
            EnumMultiPolygon(ref geom) => geom.to_json(),
            EnumGeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "FeatureCollection".to_string().to_json());
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {coordinates: Pos(vec![1., 2., 3.])};

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Account for enum namespacing changes<commit_after>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?

extern crate serialize;

use std::collections::TreeMap;
use std::option::{None, Option, Some};
use serialize::json::ToJson;
use serialize::json;

/// Pos (alias for Positions)
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Pos(pub Vec<f64>);

impl ToJson for Pos {
    fn to_json(&self) -> json::Json {
        let &Pos(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Pos {
    fn clone(&self) -> Pos {
        let &Pos(ref nums) = self;
        Pos(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Pos,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Pos> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Pos>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Pos>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Pos>,
    pub holes: Option<Vec<Vec<Pos>>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Pos>> {
        match self.holes {
            None => vec![self.exterior.clone()],
            Some(ref holes) => {
                let mut coordinates = holes.clone();
                coordinates.insert(0, self.exterior.clone());
                coordinates
            }
        }
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Pos>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            Geometry::Point(ref geom) => geom.to_json(),
            Geometry::MultiPoint(ref geom) => geom.to_json(),
            Geometry::LineString(ref geom) => geom.to_json(),
            Geometry::MultiLineString(ref geom) => geom.to_json(),
            Geometry::Polygon(ref geom) => geom.to_json(),
            Geometry::MultiPolygon(ref geom) => geom.to_json(),
            Geometry::GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "FeatureCollection".to_string().to_json());
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {coordinates: Pos(vec![1., 2., 3.])};

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>