<commit_before>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, ErrorKind, Read, Write, BufWriter};
use std::fs;
use std::process::exit;
use std::time::{Duration, Instant};

use clap::{Arg, App};

use ppbert::bertterm::BertTerm;
use ppbert::error::{BertError, Result};
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("indent-width")
             .default_value("2")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("max-terms-per-line")
             .default_value("5")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .conflicts_with("disk_log")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("disk_log")
             .help("Parses disk_log files")
             .conflicts_with("bert2")
             .short("d")
             .long("disk-log"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .short("t")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };
    let indent_level = value_t!(matches, "indent_width", usize).unwrap();
    let max_per_line = value_t!(matches, "max_per_line", usize).unwrap();
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");
    let json = matches.is_present("json");
    let transform_proplists = matches.is_present("transform-proplists");

    let parse_fn =
        if matches.is_present("bert2") {
            parser::Parser::bert2_next
        } else if matches.is_present("disk_log") {
            parser::Parser::disk_log_next
        } else {
            parser::Parser::bert_next
        };
    let output_fn = match (json, transform_proplists) {
        (true, false)  => pp_json,
        (true, true)   => pp_json_proplist,
        (false, false) => pp_bert,
        (false, true)  => {
            eprintln!("{}: --transform-proplists is only valid with the --json flag", PROG_NAME);
            pp_bert
        }
    };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(ref e) => {
                if broken_pipe(e) {
                    break;
                }
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn broken_pipe(err: &BertError) -> bool {
    match *err {
        BertError::IoError(ref ioerr) =>
            ioerr.kind() == ErrorKind::BrokenPipe,
        _ => false
    }
}

fn handle_file(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(&mut parser::Parser) -> Option<Result<BertTerm>>,
    pp_fn: fn(BertTerm, usize, usize) -> Result<()>
) -> Result<()> {

    // Read file or stdin into buffer
    let now = Instant::now();
    let buf = if file == "-" {
        let stdin = io::stdin();
        let mut stdin = stdin.lock();
        let mut buf: Vec<u8> = Vec::with_capacity(4096);
        stdin.read_to_end(&mut buf)?;
        buf
    } else {
        fs::read(file)?
    };
    let read_dur = now.elapsed();

    let mut parser = parser::Parser::new(buf);
    let mut parse_dur = Duration::new(0, 0);
    let mut pp_dur = Duration::new(0, 0);

    loop {
        let now = Instant::now();
        let next_item = parse_fn(&mut parser);
        parse_dur += now.elapsed();

        match next_item {
            None => { break; }
            Some(Err(e)) => { return Err(e); }
            Some(Ok(t)) => {
                if !parse_only {
                    let now = Instant::now();
                    pp_fn(t, indent, terms_per_line)?;
                    pp_dur += now.elapsed();
                }
            }
        }
    }

    if verbose {
        eprintln!("{}: {} read time: {}.{:06} seconds", PROG_NAME, file, read_dur.as_secs(), read_dur.subsec_micros());
        eprintln!("{}: {} parse time: {}.{:06} seconds", PROG_NAME, file, parse_dur.as_secs(), parse_dur.subsec_micros());
        if !parse_only {
            eprintln!("{}: {} print time: {}.{:06} seconds", PROG_NAME, file, pp_dur.as_secs(), pp_dur.subsec_micros());
        }
    }

    return Ok(());
}

/// Outputs a BertTerm to stdout.
fn pp_bert(term: BertTerm, indent_width: usize, terms_per_line: usize) -> Result<()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_erlang(&mut stdout, indent_width, terms_per_line)?;
    stdout.flush()?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout.
fn pp_json(term: BertTerm, _: usize, _: usize) -> Result<()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_json(&mut stdout, false)?;
    writeln!(&mut stdout, "")?;
    stdout.flush()?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout;
/// Erlang proplists are converted to JSON objects.
fn pp_json_proplist(term: BertTerm, _: usize, _: usize) -> Result<()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_json(&mut stdout, true)?;
    writeln!(&mut stdout, "")?;
    stdout.flush()?;
    return Ok(());
}
<commit_msg>Rename `indent_level` into `indent_width`<commit_after>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, ErrorKind, Read, Write, BufWriter};
use std::fs;
use std::process::exit;
use std::time::{Duration, Instant};

use clap::{Arg, App};

use ppbert::bertterm::BertTerm;
use ppbert::error::{BertError, Result};
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("indent-width")
             .default_value("2")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("max-terms-per-line")
             .default_value("5")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .conflicts_with("disk_log")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("disk_log")
             .help("Parses disk_log files")
             .conflicts_with("bert2")
             .short("d")
             .long("disk-log"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .short("t")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };
    let indent_width = value_t!(matches, "indent_width", usize).unwrap();
    let max_per_line = value_t!(matches, "max_per_line", usize).unwrap();
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");
    let json = matches.is_present("json");
    let transform_proplists = matches.is_present("transform-proplists");

    let parse_fn =
        if matches.is_present("bert2") {
            parser::Parser::bert2_next
        } else if matches.is_present("disk_log") {
            parser::Parser::disk_log_next
        } else {
            parser::Parser::bert_next
        };
    let output_fn = match (json, transform_proplists) {
        (true, false)  => pp_json,
        (true, true)   => pp_json_proplist,
        (false, false) => pp_bert,
        (false, true)  => {
            eprintln!("{}: --transform-proplists is only valid with the --json flag", PROG_NAME);
            pp_bert
        }
    };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_width, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(ref e) => {
                if broken_pipe(e) {
                    break;
                }
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn broken_pipe(err: &BertError) -> bool {
    match *err {
        BertError::IoError(ref ioerr) =>
            ioerr.kind() == ErrorKind::BrokenPipe,
        _ => false
    }
}

fn handle_file(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(&mut parser::Parser) -> Option<Result<BertTerm>>,
    pp_fn: fn(BertTerm, usize, usize) -> Result<()>
) -> Result<()> {

    // Read file or stdin into buffer
    let now = Instant::now();
    let buf = if file == "-" {
        let stdin = io::stdin();
        let mut stdin = stdin.lock();
        let mut buf: Vec<u8> = Vec::with_capacity(4096);
        stdin.read_to_end(&mut buf)?;
        buf
    } else {
        fs::read(file)?
    };
    let read_dur = now.elapsed();

    let mut parser = parser::Parser::new(buf);
    let mut parse_dur = Duration::new(0, 0);
    let mut pp_dur = Duration::new(0, 0);

    loop {
        let now = Instant::now();
        let next_item = parse_fn(&mut parser);
        parse_dur += now.elapsed();

        match next_item {
            None => { break; }
            Some(Err(e)) => { return Err(e); }
            Some(Ok(t)) => {
                if !parse_only {
                    let now = Instant::now();
                    pp_fn(t, indent, terms_per_line)?;
                    pp_dur += now.elapsed();
                }
            }
        }
    }

    if verbose {
        eprintln!("{}: {} read time: {}.{:06} seconds", PROG_NAME, file, read_dur.as_secs(), read_dur.subsec_micros());
        eprintln!("{}: {} parse time: {}.{:06} seconds", PROG_NAME, file, parse_dur.as_secs(), parse_dur.subsec_micros());
        if !parse_only {
            eprintln!("{}: {} print time: {}.{:06} seconds", PROG_NAME, file, pp_dur.as_secs(), pp_dur.subsec_micros());
        }
    }

    return Ok(());
}

/// Outputs a BertTerm to stdout.
fn pp_bert(term: BertTerm, indent_width: usize, terms_per_line: usize) -> Result<()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_erlang(&mut stdout, indent_width, terms_per_line)?;
    stdout.flush()?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout.
fn pp_json(term: BertTerm, _: usize, _: usize) -> Result<()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_json(&mut stdout, false)?;
    writeln!(&mut stdout, "")?;
    stdout.flush()?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout;
/// Erlang proplists are converted to JSON objects.
fn pp_json_proplist(term: BertTerm, _: usize, _: usize) -> Result<()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_json(&mut stdout, true)?;
    writeln!(&mut stdout, "")?;
    stdout.flush()?;
    return Ok(());
}
<|endoftext|>


<commit_before>extern crate chrono;

pub mod location;
pub mod temperature;
pub mod model;

pub use location::GpsCoordinates;
use model::ModelParams;
use chrono::*;
use std::io::{self, Write, BufRead};

fn flush() {
    io::stdout().flush().unwrap();
}

fn main() {
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();

    // User input.

    println!("==== PARAMÈTRES D'ENTRÉE ====");
    print!("latitude (en degrés) : ");
    flush();
    let lat: f64 = lines.next().unwrap().unwrap().parse().unwrap();

    print!("longitude (en degrés) : ");
    flush();
    let long: f64 = lines.next().unwrap().unwrap().parse().unwrap();

    print!("date et heure locale (e.g. \"28/11/2016 21:00:09 +09:00\"): ");
    flush();

    let local_time_string = lines.next().unwrap().unwrap();
    println!("");

    // Model.

    let local_time = DateTime::parse_from_str(&local_time_string,
                                              "%d/%m/%Y %H:%M:%S %z")
                         .unwrap();

    let coords = GpsCoordinates {
        lat: lat,
        long: long,
    };

    let input = ModelParams {
        coords: coords,
        date_time: local_time,
    };

    let start = Local::now();
    let output = model::run(input);
    let duration = Local::now() - start;

    println!("==== VARIABLES INTERMÉDIAIRES ====");
    println!("jour de l'année : {}", output.day_of_year);
    println!("équation du temps : {:.2} minutes", output.eot);
    println!("longitude du méridien local : {}°",
             output.local_meridian_long);
    println!("facteur de correction de l'heure : {:.2} minutes",
             output.time_correction_factor);
    println!("heure solaire : {:.2}h", output.solar_time);
    println!("angle horaire : {:.4}°", output.hour_angle);
    println!("angle de déclinaison de la Terre : {:.4}°",
             output.declination_angle);
    println!("angle d'élévation : {:.4}°", output.elevation_angle);
    println!("angle zénithal : {:.4}°", output.zenith_angle);
    println!("coefficient de masse atmosphérique : {:.4}",
             output.air_mass);
    print!("\n");

    println!("==== RÉSULTAT ====");

    println!("l'irradiance est de {:.2} watts par mètre carré (calculée en \
              {} µs)",
             output.irradiance,
             duration.num_microseconds().unwrap());
}
<commit_msg>masse d'air<commit_after>extern crate chrono;

pub mod location;
pub mod temperature;
pub mod model;

pub use location::GpsCoordinates;
use model::ModelParams;
use chrono::*;
use std::io::{self, Write, BufRead};

fn flush() {
    io::stdout().flush().unwrap();
}

fn main() {
    let stdin = io::stdin();
    let mut lines = stdin.lock().lines();

    // User input.

    println!("==== PARAMÈTRES D'ENTRÉE ====");
    print!("latitude (en degrés) : ");
    flush();
    let lat: f64 = lines.next().unwrap().unwrap().parse().unwrap();

    print!("longitude (en degrés) : ");
    flush();
    let long: f64 = lines.next().unwrap().unwrap().parse().unwrap();

    print!("date et heure locale (e.g. \"28/11/2016 21:00:09 +09:00\"): ");
    flush();

    let local_time_string = lines.next().unwrap().unwrap();
    println!("");

    // Model.

    let local_time = DateTime::parse_from_str(&local_time_string,
                                              "%d/%m/%Y %H:%M:%S %z")
                         .unwrap();

    let coords = GpsCoordinates {
        lat: lat,
        long: long,
    };

    let input = ModelParams {
        coords: coords,
        date_time: local_time,
    };

    let start = Local::now();
    let output = model::run(input);
    let duration = Local::now() - start;

    println!("==== VARIABLES INTERMÉDIAIRES ====");
    println!("jour de l'année : {}", output.day_of_year);
    println!("équation du temps : {:.2} minutes", output.eot);
    println!("longitude du méridien local : {}°",
             output.local_meridian_long);
    println!("facteur de correction de l'heure : {:.2} minutes",
             output.time_correction_factor);
    println!("heure solaire : {:.2}h", output.solar_time);
    println!("angle horaire : {:.4}°", output.hour_angle);
    println!("angle de déclinaison de la Terre : {:.4}°",
             output.declination_angle);
    println!("angle d'élévation : {:.4}°", output.elevation_angle);
    println!("angle zénithal : {:.4}°", output.zenith_angle);
    println!("masse d'air : {:.4}", output.air_mass);
    print!("\n");

    println!("==== RÉSULTAT ====");

    println!("l'irradiance est de {:.2} watts par mètre carré (calculée en \
              {} µs)",
             output.irradiance,
             duration.num_microseconds().unwrap());
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;

use docopt::Docopt;

use std::env;
use std::path::PathBuf;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use rustc_serialize::json;

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
Banking for your command line.

Usage:
    teller show [ --current | --business ]
    teller -h | --help
    teller -V | --version

Options:
    -h --help       Show this screen.
    -V --version    Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_show: bool,
    flag_help: bool,
    flag_version: bool,
}

#[derive(RustcEncodable, RustcDecodable)]
struct Config {
    auth_token: String,
}

fn get_config_file(config_path: &PathBuf) -> File {
    let display = config_path.display();
    let f = match File::open(&config_path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    f
}

fn get_config(config_path: &PathBuf) -> Config {
    let mut f = get_config_file(config_path);

    let display = config_path.display();
    let mut content_str = String::new();
    match f.read_to_string(&mut content_str) {
        Err(why) => panic!("couldn't read {}: {}", display, Error::description(&why)),
        Ok(_) => (),
    }

    let config: Config = json::decode(&content_str).unwrap();
    return config;
}

fn set_config(config: Config) {

}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(VERSION.map(|v| v.to_string()))
                                 .decode()
                            })
                            .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    let config_path: PathBuf = match env::home_dir() {
        Some(mut p) => {
            p.push(".tellerrc");
            p
        },
        None => panic!("Impossible to get your home directory!"),
    };

    let config = get_config(&config_path);
    println!("{}", config.auth_token);

    println!("What's the auth token?");
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => println!("{}", input),
        Err(error) => println!("error: {}", error),
    };

    ()
}
<commit_msg>wip(question): stored answer in a Config<commit_after>extern crate rustc_serialize;
extern crate docopt;

use docopt::Docopt;

use std::env;
use std::path::PathBuf;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::fs::File;
use rustc_serialize::json;

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
Banking for your command line.

Usage:
    teller show [ --current | --business ]
    teller -h | --help
    teller -V | --version

Options:
    -h --help       Show this screen.
    -V --version    Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_show: bool,
    flag_help: bool,
    flag_version: bool,
}

#[derive(RustcEncodable, RustcDecodable)]
struct Config {
    auth_token: String,
}

impl Config {
    pub fn new(auth_token: String) -> Config {
        Config {
            auth_token: auth_token,
        }
    }
}

fn get_config_file(config_path: &PathBuf) -> File {
    let display = config_path.display();
    let f = match File::open(&config_path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    f
}

fn get_config(config_path: &PathBuf) -> Config {
    let mut f = get_config_file(config_path);

    let display = config_path.display();
    let mut content_str = String::new();
    match f.read_to_string(&mut content_str) {
        Err(why) => panic!("couldn't read {}: {}", display, Error::description(&why)),
        Ok(_) => (),
    }

    let config: Config = json::decode(&content_str).unwrap();
    return config;
}

fn set_config(config: Config) {

}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(VERSION.map(|v| v.to_string()))
                                 .decode()
                            })
                            .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    let config_path: PathBuf = match env::home_dir() {
        Some(mut p) => {
            p.push(".tellerrc");
            p
        },
        None => panic!("Impossible to get your home directory!"),
    };

    let config = get_config(&config_path);
    println!("{}", config.auth_token);

    println!("What's the auth token?");
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(_) => println!("{}", input),
        Err(error) => println!("error: {}", error),
    };

    let auth_token = String::new();
    let new_config = Config::new(auth_token);

    println!("fake token: {}", new_config.auth_token);

    ()
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate rand;

use libc::funcs::posix88::unistd;
use std::ffi::CString;
use std::cmp;
use std::env;
use std::os;
use std::ptr;
use rand::Rng;

fn main() {
    let version = "0.1.0";
    let maybe_args: Option<Vec<String>> = env::args().skip(1).map(|s| { s.into_string().ok() }).collect();
    maybe_args.map_or_else(|| { die_usage(version) }, |args| {
        match parse_args(&args[]) {
            Err(Exit::Usage) => {
                die_usage(version);
            }
            Err(Exit::Help) =>
                print_usage(version),
            Err(Exit::Version) =>
                print_version(version),
            Ok(opts) => {
                if whack(&opts) {
                    env::set_exit_status(1);
                } else {
                    opts.exe.map_or((), |exe| {
                        execvp(exe.name, exe.args)
                    });
                }
            }
        }
    })
}

type ArgParse<T> = Result<T, Exit>;

#[derive(Debug)]
struct Options<'a> {
    chance: i32,
    exe: Option<Exe<'a>>,
}

#[derive(Debug)]
struct Exe<'a> {
    name: &'a str,
    args: &'a[String],
}

#[derive(Debug)]
enum Exit {
    Usage,
    Help,
    Version,
}

fn parse_args(args: &[String]) -> ArgParse<Options> {
    args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
        match &s[] {
            "--help"    | "-h" => Err(Exit::Help),
            "--version" | "-v" => Err(Exit::Version),
            "--chance"  | "-c" => {
                args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
                    s.parse().ok().map_or(Err(Exit::Usage), |val| {
                        args.skip("--").uncons().map_or(
                            Ok(Options {
                                chance: val,
                                exe: None
                            }), |(exe, args)| {
                                Ok(Options {
                                    chance: val,
                                    exe: Some(Exe {
                                        name: &exe[],
                                        args: args,
                                    })
                                })
                            })
                        })
                    })
                }
            _ => Err(Exit::Usage),
        }
    })
}

trait Uncons<'a, A> { fn uncons(&self) -> Option<(&'a A, &'a [A])>; }
trait Skip<'a, A, B> { fn skip(&self, x: A) -> &'a [B]; }

impl<'a, A> Uncons<'a, A> for &'a [A] {
    fn uncons(&self) -> Option<(&'a A, &'a [A])> {
        self.first().map(|x| (x, self.tail()))
    }
}

impl<'a > Skip<'a, &'a str, String> for &'a [String] {
    fn skip(&self, x: &'a str) -> &'a [String] {
        self.uncons().map_or(*self, |(y, ys)| { if x == &y[] { ys } else { *self } })
    }
}

fn whack(opts: &Options) -> bool {
    rand::thread_rng().gen_range(0, 100) > cmp::min(cmp::max(opts.chance, 0), 100)
}

fn execvp(name: &str, args: &[String]) {
    let c_name: CString = CString::from_slice(name.as_bytes());
    let c_args: Vec<CString> = args.iter().map(|tmp| CString::from_slice(tmp.as_bytes())).collect();

    let mut xs: Vec<*const libc::c_char> = Vec::with_capacity(args.len() + 2);

    xs.push(c_name.as_ptr());
    xs.extend(c_args.iter().map(|tmp| tmp.as_ptr()));
    xs.push(ptr::null());

    let c_arg0 = xs[0];
    let c_argv = xs.as_mut_ptr();

    unsafe {
        unistd::execvp(c_arg0, c_argv);
    };

    panic!("execvp(3) failed with: {}", os::last_os_error());
}

fn die_usage(version: &str) {
    env::set_exit_status(1);
    print_usage(version);
}

fn print_usage(version: &str) {
    print_version(version);
    println!("\n\
        Usage: whacky (-c PERCENTAGE|--chance PERCENTAGE) [[--] COMMAND]\n\
          whacky, yet another randomly failing program\n\
        \n\
        Available options:\n\
          -h,--help           show this help text\n\
          -c,--chance         set success chance");
}

fn print_version(version: &str) {
    println!("whacky {}", version);
}
<commit_msg>Version is constant<commit_after>extern crate libc;
extern crate rand;

use libc::funcs::posix88::unistd;
use std::ffi::CString;
use std::cmp;
use std::env;
use std::os;
use std::ptr;
use rand::Rng;

static VERSION: &'static str = "0.1.0";

fn main() {
    let maybe_args: Option<Vec<String>> = env::args().skip(1).map(|s| { s.into_string().ok() }).collect();
    maybe_args.map_or_else(|| { die_usage() }, |args| {
        match parse_args(&args[]) {
            Err(Exit::Usage) => {
                die_usage();
            }
            Err(Exit::Help) =>
                print_usage(),
            Err(Exit::Version) =>
                print_version(),
            Ok(opts) => {
                if whack(&opts) {
                    env::set_exit_status(1);
                } else {
                    opts.exe.map_or((), |exe| {
                        execvp(exe.name, exe.args)
                    });
                }
            }
        }
    })
}

type ArgParse<T> = Result<T, Exit>;

#[derive(Debug)]
struct Options<'a> {
    chance: i32,
    exe: Option<Exe<'a>>,
}

#[derive(Debug)]
struct Exe<'a> {
    name: &'a str,
    args: &'a[String],
}

#[derive(Debug)]
enum Exit {
    Usage,
    Help,
    Version,
}

fn parse_args(args: &[String]) -> ArgParse<Options> {
    args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
        match &s[] {
            "--help"    | "-h" => Err(Exit::Help),
            "--version" | "-v" => Err(Exit::Version),
            "--chance"  | "-c" => {
                args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
                    s.parse().ok().map_or(Err(Exit::Usage), |val| {
                        args.skip("--").uncons().map_or(
                            Ok(Options {
                                chance: val,
                                exe: None
                            }), |(exe, args)| {
                                Ok(Options {
                                    chance: val,
                                    exe: Some(Exe {
                                        name: &exe[],
                                        args: args,
                                    })
                                })
                            })
                        })
                    })
                }
            _ => Err(Exit::Usage),
        }
    })
}

trait Uncons<'a, A> { fn uncons(&self) -> Option<(&'a A, &'a [A])>; }
trait Skip<'a, A, B> { fn skip(&self, x: A) -> &'a [B]; }

impl<'a, A> Uncons<'a, A> for &'a [A] {
    fn uncons(&self) -> Option<(&'a A, &'a [A])> {
        self.first().map(|x| (x, self.tail()))
    }
}

impl<'a > Skip<'a, &'a str, String> for &'a [String] {
    fn skip(&self, x: &'a str) -> &'a [String] {
        self.uncons().map_or(*self, |(y, ys)| { if x == &y[] { ys } else { *self } })
    }
}

fn whack(opts: &Options) -> bool {
    rand::thread_rng().gen_range(0, 100) > cmp::min(cmp::max(opts.chance, 0), 100)
}

fn execvp(name: &str, args: &[String]) {
    let c_name: CString = CString::from_slice(name.as_bytes());
    let c_args: Vec<CString> = args.iter().map(|tmp| CString::from_slice(tmp.as_bytes())).collect();

    let mut xs: Vec<*const libc::c_char> = Vec::with_capacity(args.len() + 2);

    xs.push(c_name.as_ptr());
    xs.extend(c_args.iter().map(|tmp| tmp.as_ptr()));
    xs.push(ptr::null());

    let c_arg0 = xs[0];
    let c_argv = xs.as_mut_ptr();

    unsafe {
        unistd::execvp(c_arg0, c_argv);
    };

    panic!("execvp(3) failed with: {}", os::last_os_error());
}

fn die_usage() {
    env::set_exit_status(1);
    print_usage();
}

fn print_usage() {
    print_version();
    println!("\n\
        Usage: whacky (-c PERCENTAGE|--chance PERCENTAGE) [[--] COMMAND]\n\
          whacky, yet another randomly failing program\n\
        \n\
        Available options:\n\
          -h,--help           show this help text\n\
          -c,--chance         set success chance");
}

fn print_version() {
    println!("whacky {}", VERSION);
}
<|endoftext|>


<commit_before>extern crate rgmk;
extern crate clap;

use clap::{App, SubCommand, AppSettings};
use std::io::{self, stdin, stdout, stderr, BufReader};
use std::io::prelude::*;
use rgmk::GameData;
use std::path::Path;

fn main() {
    std::process::exit(run());
}

fn run() -> i32 {
    let strings_subcommand = SubCommand::with_name("strings")
                             .about("Manipulate strings")
                             .setting(AppSettings::SubcommandRequired)
                             .setting(AppSettings::ArgRequiredElseHelp)
                             .subcommand(SubCommand::with_name("dump")
                                         .about("Dump strings.")
                                         .args_from_usage("[OUTPUT_FILE] 'The file to write \
                                                           the strings to. \
                                                           By default, standard output.'"))
                             .subcommand(SubCommand::with_name("repack")
                                         .about("Repack strings")
                                         .args_from_usage("[INPUT_FILE] 'The file containing \
                                                           the strings to repack. \
                                                           By default, standard input.'"));
    let textures_subcommand = SubCommand::with_name("textures")
                              .about("Manipulate textures")
                              .setting(AppSettings::SubcommandRequired)
                              .subcommand(SubCommand::with_name("dump")
                                          .about("Dump textures"))
                              .subcommand(SubCommand::with_name("repack")
                                          .about("Repack textures"));
    let matches = App::new("gmktool")
                  .setting(AppSettings::SubcommandRequired)
                  .version(env!("CARGO_PKG_VERSION"))
                  .about("Tool for manipulating Game Maker Stdudio data files")
                  .args_from_usage("-b --backup=[BACKUP_FILE] 'Create a backup. \
                                    By default, it's DATA_FILE.bk'
                                    <DATA_FILE> 'The game maker data file to operate on'")
                  .subcommand(strings_subcommand)
                  .subcommand(textures_subcommand)
                  .get_matches();
    let data_file_path = matches.value_of("DATA_FILE").unwrap();
    let backup = matches.is_present("backup");
    let backup_path = format!("{}.bk", data_file_path);
    let backup_path = matches.value_of("BACKUP_FILE").unwrap_or(&backup_path);
    let mut game_data = match GameData::from_file(data_file_path) {
        Ok(g) => g,
        Err(e) => {
            writeln!(stderr(),
                     "Failed to load game data for {:?}: {}", data_file_path, e).unwrap();
            return 1;
        }
    };
    if let Some(matches) = matches.subcommand_matches("strings") {
        if let Some(matches) = matches.subcommand_matches("dump") {
            match matches.value_of("OUTPUT_FILE") {
                Some(path) => {
                    let mut file = match std::fs::File::create(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to create output file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = dump_strings(&game_data, &mut file) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
                None => {
                    let stdout = stdout();
                    let mut lock = stdout.lock();
                    if let Err(e) = dump_strings(&game_data, &mut lock) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
            }
        } else if let Some(matches) = matches.subcommand_matches("repack") {
            if backup {
                if let Err(e) = std::fs::copy(data_file_path, backup_path) {
                    writeln!(stderr(), "Failed to create backup: {}", e).unwrap();
                }
            }
            match matches.value_of("INPUT_FILE") {
                Some(path) => {
                    let file = match std::fs::File::open(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to open input file: {}", e)
                                .unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(file),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
                None => {
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(stdin()),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("textures") {
        if let Some(_) = matches.subcommand_matches("dump") {
            if let Err(e) = dump_textures(&game_data) {
                writeln!(stderr(), "Failed to dump textures: {}", e).unwrap();
                return 1;
            }
        } else if let Some(_) = matches.subcommand_matches("repack") {
            if let Err(e) = repack_textures(&mut game_data, data_file_path) {
                writeln!(stderr(), "Failed to repack textures: {}", e).unwrap();
            }
        }
    }
    0
}

fn dump_strings<W: Write>(game_data: &GameData, writer: &mut W) -> io::Result<()> {
    for s in &game_data.strings.strings {
        try!(writeln!(writer, "{}", s));
    }
    Ok(())
}

fn repack_strings<R: BufRead, P: AsRef<Path>>(game_data: &mut GameData,
                                              reader: &mut R,
                                              path: P) -> io::Result<()> {
    for (s, l) in game_data.strings.strings.iter_mut().zip(reader.lines()) {
        *s = try!(l);
    }
    game_data.save_to_file(path)
}

fn dump_textures(game_data: &GameData) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::create(path));
        try!(f.write_all(&t.png_data));
    }
    Ok(())
}

fn repack_textures<P: AsRef<Path>>(game_data: &mut GameData, path: P) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter_mut().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::open(path));
        let mut png_data = Vec::new();
        try!(f.read_to_end(&mut png_data));
        (*t).png_data = png_data;
    }
    game_data.save_to_file(path)
}
<commit_msg>Format source code with rustfmt<commit_after>extern crate rgmk;
extern crate clap;

use clap::{App, SubCommand, AppSettings};
use std::io::{self, stdin, stdout, stderr, BufReader};
use std::io::prelude::*;
use rgmk::GameData;
use std::path::Path;

fn main() {
    std::process::exit(run());
}

fn run() -> i32 {
    let strings_subcommand = SubCommand::with_name("strings")
                                 .about("Manipulate strings")
                                 .setting(AppSettings::SubcommandRequired)
                                 .setting(AppSettings::ArgRequiredElseHelp)
                                 .subcommand(SubCommand::with_name("dump")
                                                 .about("Dump strings.")
                                                 .args_from_usage("[OUTPUT_FILE] 'The file to \
                                                                   write the strings to. By \
                                                                   default, standard output.'"))
                                 .subcommand(SubCommand::with_name("repack")
                                                 .about("Repack strings")
                                                 .args_from_usage("[INPUT_FILE] 'The file \
                                                                   containing the strings to \
                                                                   repack. By default, standard \
                                                                   input.'"));
    let textures_subcommand = SubCommand::with_name("textures")
                                  .about("Manipulate textures")
                                  .setting(AppSettings::SubcommandRequired)
                                  .subcommand(SubCommand::with_name("dump").about("Dump textures"))
                                  .subcommand(SubCommand::with_name("repack")
                                                  .about("Repack textures"));
    let matches = App::new("gmktool")
                      .setting(AppSettings::SubcommandRequired)
                      .version(env!("CARGO_PKG_VERSION"))
                      .about("Tool for manipulating Game Maker Stdudio data files")
                      .args_from_usage("-b --backup=[BACKUP_FILE] 'Create a backup. By default, \
                                        it's DATA_FILE.bk'
                                    \
                                        <DATA_FILE> 'The game maker data file to operate on'")
                      .subcommand(strings_subcommand)
                      .subcommand(textures_subcommand)
                      .get_matches();
    let data_file_path = matches.value_of("DATA_FILE").unwrap();
    let backup = matches.is_present("backup");
    let backup_path = format!("{}.bk", data_file_path);
    let backup_path = matches.value_of("BACKUP_FILE").unwrap_or(&backup_path);
    let mut game_data = match GameData::from_file(data_file_path) {
        Ok(g) => g,
        Err(e) => {
            writeln!(stderr(),
                     "Failed to load game data for {:?}: {}",
                     data_file_path,
                     e)
                .unwrap();
            return 1;
        }
    };
    if let Some(matches) = matches.subcommand_matches("strings") {
        if let Some(matches) = matches.subcommand_matches("dump") {
            match matches.value_of("OUTPUT_FILE") {
                Some(path) => {
                    let mut file = match std::fs::File::create(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to create output file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = dump_strings(&game_data, &mut file) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
                None => {
                    let stdout = stdout();
                    let mut lock = stdout.lock();
                    if let Err(e) = dump_strings(&game_data, &mut lock) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
            }
        } else if let Some(matches) = matches.subcommand_matches("repack") {
            if backup {
                if let Err(e) = std::fs::copy(data_file_path, backup_path) {
                    writeln!(stderr(), "Failed to create backup: {}", e).unwrap();
                }
            }
            match matches.value_of("INPUT_FILE") {
                Some(path) => {
                    let file = match std::fs::File::open(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to open input file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(file),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
                None => {
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(stdin()),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("textures") {
        if let Some(_) = matches.subcommand_matches("dump") {
            if let Err(e) = dump_textures(&game_data) {
                writeln!(stderr(), "Failed to dump textures: {}", e).unwrap();
                return 1;
            }
        } else if let Some(_) = matches.subcommand_matches("repack") {
            if let Err(e) = repack_textures(&mut game_data, data_file_path) {
                writeln!(stderr(), "Failed to repack textures: {}", e).unwrap();
            }
        }
    }
    0
}

fn dump_strings<W: Write>(game_data: &GameData, writer: &mut W) -> io::Result<()> {
    for s in &game_data.strings.strings {
        try!(writeln!(writer, "{}", s));
    }
    Ok(())
}

fn repack_strings<R: BufRead, P: AsRef<Path>>(game_data: &mut GameData,
                                              reader: &mut R,
                                              path: P)
                                              -> io::Result<()> {
    for (s, l) in game_data.strings.strings.iter_mut().zip(reader.lines()) {
        *s = try!(l);
    }
    game_data.save_to_file(path)
}

fn dump_textures(game_data: &GameData) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::create(path));
        try!(f.write_all(&t.png_data));
    }
    Ok(())
}

fn repack_textures<P: AsRef<Path>>(game_data: &mut GameData, path: P) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter_mut().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::open(path));
        let mut png_data = Vec::new();
        try!(f.read_to_end(&mut png_data));
        (*t).png_data = png_data;
    }
    game_data.save_to_file(path)
}
<|endoftext|>


<commit_before>//! A module of helper traits and iterators that are not intended to be used
//! directly.

use std::ops::{
    RangeFull,
    Range,
    RangeTo,
    RangeFrom
};

use std::mem;
use std::slice;

/// Apply `IntoIterator` on each element of a tuple.
pub trait IntoIteratorTuple
{
    /// Tuple of values that implement `Iterator`.
    type Output;

    /// Return a tuple of iterators.
    fn into_iterator_tuple(self) -> Self::Output;
}

/// A helper trait for (x, y, z) ++ w => (x, y, z, w),
/// used for implementing `iproduct!`.
pub trait AppendTuple<X> {
    /// Resulting tuple type
    type Result;
    /// “Append” value `x` to a tuple.
    fn append(self, x: X) -> Self::Result;
}

macro_rules! impl_append_tuple(
    () => (
        impl<T> AppendTuple<T> for () {
            type Result = (T, );
            fn append(self, x: T) -> (T, ) {
                (x, )
            }
        }
    );

    ($A:ident, $($B:ident,)*) => (
        impl_append_tuple!($($B,)*);
        #[allow(non_snake_case)]
        impl<$A, $($B,)* T> AppendTuple<T> for ($A, $($B),*) {
            type Result = ($A, $($B, )* T);
            fn append(self, x: T) -> ($A, $($B,)* T) {
                let ($A, $($B),*) = self;
                ($A, $($B,)* x)
            }
        }
    );
);

impl_append_tuple!(A, B, C, D, E, F, G, H, I, J, K, L,);

/// A helper iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[derive(Clone)]
pub struct FlatTuples<I> {
    iter: I,
}

impl<I> FlatTuples<I>
{
    /// Create a new `FlatTuples`.
    #[doc(hidden)]
    pub fn new(iter: I) -> Self
    {
        FlatTuples{iter: iter}
    }
}

impl<X, T, I> Iterator for FlatTuples<I> where
    I: Iterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    type Item = T::Result;
    #[inline]
    fn next(&mut self) -> Option<Self::Item>
    {
        self.iter.next().map(|(t, x)| t.append(x))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<X, T, I> DoubleEndedIterator for FlatTuples<I> where
    I: DoubleEndedIterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item>
    {
        self.iter.next_back().map(|(t, x)| t.append(x))
    }
}

/// `GenericRange` is implemented by Rust's built-in range types, produced
/// by range syntax like `a..`, `..b` or `c..d`.
pub trait GenericRange {
    #[doc(hidden)]
    /// Start index (inclusive)
    fn start(&self) -> Option<usize> { None }
    #[doc(hidden)]
    /// End index (exclusive)
    fn end(&self) -> Option<usize> { None }
}

impl GenericRange for RangeFull {}

impl GenericRange for RangeFrom<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
}

impl GenericRange for RangeTo<usize> {
    fn end(&self) -> Option<usize> { Some(self.end) }
}

impl GenericRange for Range<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
    fn end(&self) -> Option<usize> { Some(self.end) }
}

/// Helper trait to convert usize to floating point type.
pub trait ToFloat<F> : Copy {
    #[doc(hidden)]
    /// Convert usize to float.
    fn to_float(self) -> F;
}

impl ToFloat<f32> for usize {
    fn to_float(self) -> f32 { self as f32 }
}

impl ToFloat<f64> for usize {
    fn to_float(self) -> f64 { self as f64 }
}

/// A trait for items that can *maybe* be joined together.
pub trait MendSlice
{
    #[doc(hidden)]
    /// If the slices are contiguous, return them joined into one.
    fn mend(Self, Self) -> Result<Self, (Self, Self)> where Self: Sized;
}

impl<'a, T> MendSlice for &'a [T]
{
    #[inline]
    fn mend(a: Self, b: Self) -> Result<Self, (Self, Self)>
    {
        unsafe {
            let a_end = a.as_ptr().offset(a.len() as isize);
            if a_end == b.as_ptr() {
                Ok(slice::from_raw_parts(a.as_ptr(), a.len() + b.len()))
            } else {
                Err((a, b))
            }
        }
    }
}

impl<'a, T> MendSlice for &'a mut [T]
{
    #[inline]
    fn mend(a: Self, b: Self) -> Result<Self, (Self, Self)>
    {
        unsafe {
            let a_end = a.as_ptr().offset(a.len() as isize);
            if a_end == b.as_ptr() {
                Ok(slice::from_raw_parts_mut(a.as_mut_ptr(), a.len() + b.len()))
            } else {
                Err((a, b))
            }
        }
    }
}

impl<'a> MendSlice for &'a str
{
    #[inline]
    fn mend(a: Self, b: Self) -> Result<Self, (Self, Self)>
    {
        unsafe {
            mem::transmute(MendSlice::mend(a.as_bytes(), b.as_bytes()))
        }
    }
}

/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
///
/// Unsafe trait because:
///
/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
pub unsafe trait Slice {
    /// The type of a reference to the slice's elements
    type Item;
    #[doc(hidden)]
    fn len(&self) -> usize;
    #[doc(hidden)]
    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
}

unsafe impl<'a, T> Slice for &'a [T] {
    type Item = &'a T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
        debug_assert!(i < self.len());
        (**self).get_unchecked(i)
    }
}

unsafe impl<'a, T> Slice for &'a mut [T] {
    type Item = &'a mut T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
        debug_assert!(i < self.len());
        // override the lifetime constraints of &mut &'a mut [T]
        (*(*self as *mut [T])).get_unchecked_mut(i)
    }
}
<commit_msg>Mark to_float inline<commit_after>//! A module of helper traits and iterators that are not intended to be used
//! directly.

use std::ops::{
    RangeFull,
    Range,
    RangeTo,
    RangeFrom
};

use std::mem;
use std::slice;

/// Apply `IntoIterator` on each element of a tuple.
pub trait IntoIteratorTuple
{
    /// Tuple of values that implement `Iterator`.
    type Output;

    /// Return a tuple of iterators.
    fn into_iterator_tuple(self) -> Self::Output;
}

/// A helper trait for (x, y, z) ++ w => (x, y, z, w),
/// used for implementing `iproduct!`.
pub trait AppendTuple<X> {
    /// Resulting tuple type
    type Result;
    /// “Append” value `x` to a tuple.
    fn append(self, x: X) -> Self::Result;
}

macro_rules! impl_append_tuple(
    () => (
        impl<T> AppendTuple<T> for () {
            type Result = (T, );
            fn append(self, x: T) -> (T, ) {
                (x, )
            }
        }
    );

    ($A:ident, $($B:ident,)*) => (
        impl_append_tuple!($($B,)*);
        #[allow(non_snake_case)]
        impl<$A, $($B,)* T> AppendTuple<T> for ($A, $($B),*) {
            type Result = ($A, $($B, )* T);
            fn append(self, x: T) -> ($A, $($B,)* T) {
                let ($A, $($B),*) = self;
                ($A, $($B,)* x)
            }
        }
    );
);

impl_append_tuple!(A, B, C, D, E, F, G, H, I, J, K, L,);

/// A helper iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[derive(Clone)]
pub struct FlatTuples<I> {
    iter: I,
}

impl<I> FlatTuples<I>
{
    /// Create a new `FlatTuples`.
    #[doc(hidden)]
    pub fn new(iter: I) -> Self
    {
        FlatTuples{iter: iter}
    }
}

impl<X, T, I> Iterator for FlatTuples<I> where
    I: Iterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    type Item = T::Result;
    #[inline]
    fn next(&mut self) -> Option<Self::Item>
    {
        self.iter.next().map(|(t, x)| t.append(x))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<X, T, I> DoubleEndedIterator for FlatTuples<I> where
    I: DoubleEndedIterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item>
    {
        self.iter.next_back().map(|(t, x)| t.append(x))
    }
}

/// `GenericRange` is implemented by Rust's built-in range types, produced
/// by range syntax like `a..`, `..b` or `c..d`.
pub trait GenericRange {
    #[doc(hidden)]
    /// Start index (inclusive)
    fn start(&self) -> Option<usize> { None }
    #[doc(hidden)]
    /// End index (exclusive)
    fn end(&self) -> Option<usize> { None }
}

impl GenericRange for RangeFull {}

impl GenericRange for RangeFrom<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
}

impl GenericRange for RangeTo<usize> {
    fn end(&self) -> Option<usize> { Some(self.end) }
}

impl GenericRange for Range<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
    fn end(&self) -> Option<usize> { Some(self.end) }
}

/// Helper trait to convert usize to floating point type.
pub trait ToFloat<F> : Copy {
    #[doc(hidden)]
    /// Convert usize to float.
    fn to_float(self) -> F;
}

impl ToFloat<f32> for usize {
    #[inline(always)]
    fn to_float(self) -> f32 { self as f32 }
}

impl ToFloat<f64> for usize {
    #[inline(always)]
    fn to_float(self) -> f64 { self as f64 }
}

/// A trait for items that can *maybe* be joined together.
pub trait MendSlice
{
    #[doc(hidden)]
    /// If the slices are contiguous, return them joined into one.
    fn mend(Self, Self) -> Result<Self, (Self, Self)> where Self: Sized;
}

impl<'a, T> MendSlice for &'a [T]
{
    #[inline]
    fn mend(a: Self, b: Self) -> Result<Self, (Self, Self)>
    {
        unsafe {
            let a_end = a.as_ptr().offset(a.len() as isize);
            if a_end == b.as_ptr() {
                Ok(slice::from_raw_parts(a.as_ptr(), a.len() + b.len()))
            } else {
                Err((a, b))
            }
        }
    }
}

impl<'a, T> MendSlice for &'a mut [T]
{
    #[inline]
    fn mend(a: Self, b: Self) -> Result<Self, (Self, Self)>
    {
        unsafe {
            let a_end = a.as_ptr().offset(a.len() as isize);
            if a_end == b.as_ptr() {
                Ok(slice::from_raw_parts_mut(a.as_mut_ptr(), a.len() + b.len()))
            } else {
                Err((a, b))
            }
        }
    }
}

impl<'a> MendSlice for &'a str
{
    #[inline]
    fn mend(a: Self, b: Self) -> Result<Self, (Self, Self)>
    {
        unsafe {
            mem::transmute(MendSlice::mend(a.as_bytes(), b.as_bytes()))
        }
    }
}

/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
///
/// Unsafe trait because:
///
/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
pub unsafe trait Slice {
    /// The type of a reference to the slice's elements
    type Item;
    #[doc(hidden)]
    fn len(&self) -> usize;
    #[doc(hidden)]
    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
}

unsafe impl<'a, T> Slice for &'a [T] {
    type Item = &'a T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
        debug_assert!(i < self.len());
        (**self).get_unchecked(i)
    }
}

unsafe impl<'a, T> Slice for &'a mut [T] {
    type Item = &'a mut T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
        debug_assert!(i < self.len());
        // override the lifetime constraints of &mut &'a mut [T]
        (*(*self as *mut [T])).get_unchecked_mut(i)
    }
}
<|endoftext|>


<commit_before>use clap::{AppSettings, Parser};
use std::fmt::{self, Display};
use std::path::PathBuf;
use std::str::FromStr;
use syn_select::Selector;

#[derive(Parser)]
#[clap(bin_name = "cargo", version, author)]
pub enum Opts {
    /// Show the result of macro expansion.
    #[clap(
        name = "expand",
        version,
        author,
        setting = AppSettings::DeriveDisplayOrder,
        dont_collapse_args_in_usage = true
    )]
    Expand(Args),
}

#[derive(Parser, Debug)]
pub struct Args {
    /// Space-separated list of features to activate
    #[clap(long, value_name = "FEATURES", action)]
    pub features: Option<String>,

    /// Activate all available features
    #[clap(long, action)]
    pub all_features: bool,

    /// Do not activate the `default` feature
    #[clap(long, action)]
    pub no_default_features: bool,

    /// Expand only this package's library
    #[clap(long, action)]
    pub lib: bool,

    /// Expand only the specified binary
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false, action)]
    pub bin: Option<Option<String>>,

    /// Expand only the specified example
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false, action)]
    pub example: Option<Option<String>>,

    /// Expand only the specified test target
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false, action)]
    pub test: Option<Option<String>>,

    /// Include tests when expanding the lib or bin
    #[clap(long, action)]
    pub tests: bool,

    /// Expand only the specified bench target
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false, action)]
    pub bench: Option<Option<String>>,

    /// Target triple which compiles will be for
    #[clap(long, value_name = "TARGET", action)]
    pub target: Option<String>,

    /// Directory for all generated artifacts
    #[clap(long, value_name = "DIRECTORY", action)]
    pub target_dir: Option<PathBuf>,

    /// Path to Cargo.toml
    #[clap(long, value_name = "PATH", action)]
    pub manifest_path: Option<PathBuf>,

    /// Package to expand
    #[clap(
        short,
        long,
        value_name = "SPEC",
        min_values = 0,
        multiple_values = false,
        action
    )]
    pub package: Option<Option<String>>,

    /// Build artifacts in release mode, with optimizations
    #[clap(long, action)]
    pub release: bool,

    /// Number of parallel jobs, defaults to # of CPUs
    #[clap(short, long, value_name = "N", action)]
    pub jobs: Option<u64>,

    /// Print command lines as they are executed
    #[clap(long, action)]
    pub verbose: bool,

    /// Coloring: auto, always, never
    #[clap(long, value_name = "WHEN", action)]
    pub color: Option<Coloring>,

    /// Require Cargo.lock and cache are up to date
    #[clap(long, action)]
    pub frozen: bool,

    /// Require Cargo.lock is up to date
    #[clap(long, action)]
    pub locked: bool,

    /// Run without accessing the network
    #[clap(long, action)]
    pub offline: bool,

    /// Unstable (nightly-only) flags to Cargo
    #[clap(short = 'Z', value_name = "FLAG", action)]
    pub unstable_flags: Vec<String>,

    /// Do not attempt to run rustfmt
    #[clap(long, action)]
    pub ugly: bool,

    /// Select syntax highlighting theme
    #[clap(long, value_name = "NAME", action)]
    pub theme: Option<String>,

    /// Print available syntax highlighting theme names
    #[clap(long, action)]
    pub themes: bool,

    /// Local path to module or other named item to expand, e.g. os::unix::ffi
    #[clap(value_name = "ITEM", value_parser = parse_selector)]
    pub item: Option<Selector>,
}

#[derive(Debug, Clone, Copy)]
pub enum Coloring {
    Auto,
    Always,
    Never,
}

impl FromStr for Coloring {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name {
            "auto" => Ok(Coloring::Auto),
            "always" => Ok(Coloring::Always),
            "never" => Ok(Coloring::Never),
            other => Err(format!(
                "must be auto, always, or never, but found `{}`",
                other,
            )),
        }
    }
}

impl Display for Coloring {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Coloring::Auto => "auto",
            Coloring::Always => "always",
            Coloring::Never => "never",
        };
        formatter.write_str(name)
    }
}

fn parse_selector(s: &str) -> Result<Selector, <Selector as FromStr>::Err> {
    if s.starts_with("::") {
        s[2..].parse()
    } else {
        s.parse()
    }
}

#[test]
fn test_cli() {
    <Opts as clap::CommandFactory>::command().debug_assert();
}
<commit_msg>Format clap attributes with rustfmt 1.4.38<commit_after>use clap::{AppSettings, Parser};
use std::fmt::{self, Display};
use std::path::PathBuf;
use std::str::FromStr;
use syn_select::Selector;

#[derive(Parser)]
#[clap(bin_name = "cargo", version, author)]
pub enum Opts {
    /// Show the result of macro expansion.
    #[clap(
        name = "expand",
        version,
        author,
        setting = AppSettings::DeriveDisplayOrder,
        dont_collapse_args_in_usage = true
    )]
    Expand(Args),
}

#[derive(Parser, Debug)]
pub struct Args {
    /// Space-separated list of features to activate
    #[clap(long, value_name = "FEATURES", action)]
    pub features: Option<String>,

    /// Activate all available features
    #[clap(long, action)]
    pub all_features: bool,

    /// Do not activate the `default` feature
    #[clap(long, action)]
    pub no_default_features: bool,

    /// Expand only this package's library
    #[clap(long, action)]
    pub lib: bool,

    /// Expand only the specified binary
    #[clap(
        long,
        value_name = "NAME",
        min_values = 0,
        multiple_values = false,
        action
    )]
    pub bin: Option<Option<String>>,

    /// Expand only the specified example
    #[clap(
        long,
        value_name = "NAME",
        min_values = 0,
        multiple_values = false,
        action
    )]
    pub example: Option<Option<String>>,

    /// Expand only the specified test target
    #[clap(
        long,
        value_name = "NAME",
        min_values = 0,
        multiple_values = false,
        action
    )]
    pub test: Option<Option<String>>,

    /// Include tests when expanding the lib or bin
    #[clap(long, action)]
    pub tests: bool,

    /// Expand only the specified bench target
    #[clap(
        long,
        value_name = "NAME",
        min_values = 0,
        multiple_values = false,
        action
    )]
    pub bench: Option<Option<String>>,

    /// Target triple which compiles will be for
    #[clap(long, value_name = "TARGET", action)]
    pub target: Option<String>,

    /// Directory for all generated artifacts
    #[clap(long, value_name = "DIRECTORY", action)]
    pub target_dir: Option<PathBuf>,

    /// Path to Cargo.toml
    #[clap(long, value_name = "PATH", action)]
    pub manifest_path: Option<PathBuf>,

    /// Package to expand
    #[clap(
        short,
        long,
        value_name = "SPEC",
        min_values = 0,
        multiple_values = false,
        action
    )]
    pub package: Option<Option<String>>,

    /// Build artifacts in release mode, with optimizations
    #[clap(long, action)]
    pub release: bool,

    /// Number of parallel jobs, defaults to # of CPUs
    #[clap(short, long, value_name = "N", action)]
    pub jobs: Option<u64>,

    /// Print command lines as they are executed
    #[clap(long, action)]
    pub verbose: bool,

    /// Coloring: auto, always, never
    #[clap(long, value_name = "WHEN", action)]
    pub color: Option<Coloring>,

    /// Require Cargo.lock and cache are up to date
    #[clap(long, action)]
    pub frozen: bool,

    /// Require Cargo.lock is up to date
    #[clap(long, action)]
    pub locked: bool,

    /// Run without accessing the network
    #[clap(long, action)]
    pub offline: bool,

    /// Unstable (nightly-only) flags to Cargo
    #[clap(short = 'Z', value_name = "FLAG", action)]
    pub unstable_flags: Vec<String>,

    /// Do not attempt to run rustfmt
    #[clap(long, action)]
    pub ugly: bool,

    /// Select syntax highlighting theme
    #[clap(long, value_name = "NAME", action)]
    pub theme: Option<String>,

    /// Print available syntax highlighting theme names
    #[clap(long, action)]
    pub themes: bool,

    /// Local path to module or other named item to expand, e.g. os::unix::ffi
    #[clap(value_name = "ITEM", value_parser = parse_selector)]
    pub item: Option<Selector>,
}

#[derive(Debug, Clone, Copy)]
pub enum Coloring {
    Auto,
    Always,
    Never,
}

impl FromStr for Coloring {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name {
            "auto" => Ok(Coloring::Auto),
            "always" => Ok(Coloring::Always),
            "never" => Ok(Coloring::Never),
            other => Err(format!(
                "must be auto, always, or never, but found `{}`",
                other,
            )),
        }
    }
}

impl Display for Coloring {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Coloring::Auto => "auto",
            Coloring::Always => "always",
            Coloring::Never => "never",
        };
        formatter.write_str(name)
    }
}

fn parse_selector(s: &str) -> Result<Selector, <Selector as FromStr>::Err> {
    if s.starts_with("::") {
        s[2..].parse()
    } else {
        s.parse()
    }
}

#[test]
fn test_cli() {
    <Opts as clap::CommandFactory>::command().debug_assert();
}
<|endoftext|>


<commit_before>use piston::event::*;
use piston::input::Button::Keyboard;
use piston::input::keyboard::Key;
use glutin_window::GlutinWindow as Window;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use game_object::GameObject;

static OPENGL_VERSION: OpenGL = OpenGL::_3_2;
static SIZE: [u32; 2] = [512, 512];
static PADDLE_SIZE: [f64; 2] = [8.0, 32.0];
static PADDLE_ACCEL: f64 = 4000.0;
static PADDLE_FRICTION: f64 = 0.5;
static PADDLE_MAX_SPEED: f64 = 400.0;
static BALL_SIZE: [f64; 2] = [8.0, 8.0];
static BALL_START_MAX_ANGLE: f64 = 60.0;
static BALL_START_SPEED: f64 = 250.0;

struct Pong {
    gl: GlGraphics,
    p1: GameObject,
    p2: GameObject,
    ball: GameObject,
    up: bool,
    down: bool,
    server: Player
}

enum Player {
    Left,
    Right
}

impl Pong {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

        let p1_rect = [0.0, 0.0, self.p1.size[0], self.p1.size[1]];
        let p2_rect = [0.0, 0.0, self.p2.size[0], self.p2.size[1]];
        let ball_rect = [0.0, 0.0, self.ball.size[0], self.ball.size[1]];
        let ball = &mut self.ball;
        let p1 = &mut self.p1;
        let p2 = &mut self.p2;

        self.gl.draw(args.viewport(), |c, gl| {
            clear(BLACK, gl);

            let transform = c.transform.trans(ball.pos[0], ball.pos[1])
                .trans(-ball.size[0]/2.0, -ball.size[1]/2.0);
            rectangle(WHITE, ball_rect, transform, gl);

            let transform = c.transform.trans(p1.pos[0], p1.pos[1])
                .trans(-p1.size[0]/2.0, -p1.size[1]/2.0);
            rectangle(WHITE, p1_rect, transform, gl);

            let transform = c.transform.trans(p2.pos[0], p2.pos[1])
                .trans(-p2.size[0]/2.0, -p2.size[1]/2.0);
            rectangle(WHITE, p2_rect, transform, gl);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        let (ai_up, ai_down) = self.handle_ai_paddle();

        Pong::handle_paddle(&mut self.p1, self.up, self.down, args.dt);
        Pong::handle_paddle(&mut self.p2, ai_up, ai_down, args.dt);
        Pong::handle_game_object(&mut self.p1, args.dt, false);
        Pong::handle_game_object(&mut self.p2, args.dt, false);
        Pong::handle_game_object(&mut self.ball, args.dt, true);
        self.handle_ball();
    }

    fn start(&mut self) {
        self.p1.pos = [self.p1.size[0] / 2.0 + 4.0, (SIZE[1] / 2) as f64];
        self.p2.pos = [SIZE[0] as f64 - self.p2.size[0] / 2.0 - 4.0,
            (SIZE[1] / 2) as f64];

        self.reset();
    }

    fn reset(&mut self) {
        use std::f64::consts::PI;
        use rand;
        use rand::Rng;

        self.ball.pos = [(SIZE[0] / 2) as f64, (SIZE[1] / 2) as f64];

        let mut rng = rand::thread_rng();
        let max_angle = 2.0 * BALL_START_MAX_ANGLE * PI / 180.0;
        let angle = rng.next_f64() * max_angle - max_angle / 2.0;
        self.ball.vel = [
            angle.cos() * BALL_START_SPEED * self.serve_direction(),
            angle.sin() * BALL_START_SPEED
        ];
    }

    fn serve_direction(&mut self) -> f64 {
        match self.server {
            Player::Left => { -1.0 }
            Player::Right => { 1.0 }
        }
    }

    fn key_press(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true; }
            Key::Down => { self.down = true; }
            _ => {}
        }
    }

    fn key_release(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false; }
            Key::Down => { self.down = false; }
            _ => {}
        }
    }

    fn handle_game_object(obj: &mut GameObject, dt: f64, bounce: bool) {
        obj.pos[0] += obj.vel[0] * dt;
        obj.pos[1] += obj.vel[1] * dt;

        if obj.pos[1] + obj.size[1] / 2.0 >= SIZE[1] as f64 {
            obj.pos[1] = SIZE[1] as f64 - obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }

        if obj.pos[1] - obj.size[1] / 2.0 <= 0.0f64 {
            obj.pos[1] = obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }
    }

    fn handle_paddle(paddle: &mut GameObject, up: bool, down: bool, dt: f64) {
        if up {
            paddle.vel[1] -= PADDLE_ACCEL * dt;
        } else if down {
            paddle.vel[1] += PADDLE_ACCEL * dt;
        } else {
            let dv = -paddle.vel[1].signum() * PADDLE_ACCEL * dt;

            if dv.abs() >= paddle.vel[1].abs() { paddle.vel[1] = 0.0; }
            else { paddle.vel[1] += dv; }
        }

        if paddle.vel[1] > PADDLE_MAX_SPEED {
            paddle.vel[1] = PADDLE_MAX_SPEED;
        } else if paddle.vel[1] < -PADDLE_MAX_SPEED {
            paddle.vel[1] = -PADDLE_MAX_SPEED;
        }
    }

    fn handle_ai_paddle(&self) -> (bool, bool) {
        let mut ai_up = false;
        let mut ai_down = false;

        if self.ball.vel[0] > 0.0 {
            if self.ball.pos[1] > self.p2.pos[1] { ai_down = true; }
            else if self.ball.pos[1] < self.p2.pos[1] { ai_up = true; }
        }

        (ai_up, ai_down)
    }

    fn handle_ball(&mut self) {
        for paddle in [&self.p1, &self.p2].iter() {
            match self.ball.collision_normal(paddle) {
                Some(normal) => {
                    let dot = self.ball.vel[0] * normal[0] +
                        self.ball.vel[1] * normal[1];

                    // reflect ball's velocity off collision normal
                    self.ball.vel = [
                        self.ball.vel[0] - 2.0 * normal[0] * dot,
                        self.ball.vel[1] - 2.0 * normal[1] * dot
                    ];

                    // apply a bit of paddle velocity to ball
                    if normal[0] != 0.0 {
                        self.ball.vel[1] += paddle.vel[1] * PADDLE_FRICTION;
                    }

                    Pong::correct_collision(&mut self.ball, paddle, normal);
                }

                None => {}
            }
        }

        if self.ball.pos[0] > SIZE[0] as f64 { self.score(Player::Left); }
        else if self.ball.pos[0] < 0.0 { self.score(Player::Right); }
    }

    fn correct_collision(a: &mut GameObject, b: &GameObject, normal: [f64; 2]) {
        if normal == [1.0, 0.0] {
            a.pos[0] = b.pos[0] + b.size[0] / 2.0 + a.size[0] / 2.0;
        } else if normal == [-1.0, 0.0] {
            a.pos[0] = b.pos[0] - b.size[0] / 2.0 - a.size[0] / 2.0;
        } else if normal == [0.0, 1.0] {
            a.pos[1] = b.pos[1] + b.size[1] / 2.0 + a.size[1] / 2.0;
        } else if normal == [0.0, -1.0] {
            a.pos[1] = b.pos[1] - b.size[1] / 2.0 - a.size[1] / 2.0;
        }
    }

    fn score(&mut self, player: Player) {
        match player {
            Player::Left => {
                self.server = Player::Right;
            }

            Player::Right => {
                self.server = Player::Left;
            }
        }

        self.reset();
    }
}

pub fn play() {

    let window = Window::new(OPENGL_VERSION,
        WindowSettings::new("pong", SIZE)
        .exit_on_esc(true));

    let mut pong = Pong {
        gl: GlGraphics::new(OPENGL_VERSION),
        p1: GameObject { size: PADDLE_SIZE, ..Default::default() },
        p2: GameObject { size: PADDLE_SIZE, ..Default::default() },
        ball: GameObject { size: BALL_SIZE, ..Default::default() },
        up: false,
        down: false,
        server: Player::Left
    };

    pong.start();

    for e in window.events() {
        if let Some(r) = e.render_args() { pong.render(&r); }
        if let Some(u) = e.update_args() { pong.update(&u); }
        if let Some(Keyboard(key)) = e.press_args() { pong.key_press(key); }
        if let Some(Keyboard(key)) = e.release_args() { pong.key_release(key); }
    }
}
<commit_msg>Added AI leading<commit_after>use piston::event::*;
use piston::input::Button::Keyboard;
use piston::input::keyboard::Key;
use glutin_window::GlutinWindow as Window;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use game_object::GameObject;

static OPENGL_VERSION: OpenGL = OpenGL::_3_2;
static SIZE: [u32; 2] = [512, 512];
static PADDLE_SIZE: [f64; 2] = [8.0, 32.0];
static PADDLE_ACCEL: f64 = 4000.0;
static PADDLE_FRICTION: f64 = 0.5;
static PADDLE_MAX_SPEED: f64 = 400.0;
static BALL_SIZE: [f64; 2] = [8.0, 8.0];
static BALL_START_MAX_ANGLE: f64 = 60.0;
static BALL_START_SPEED: f64 = 250.0;

struct Pong {
    gl: GlGraphics,
    p1: GameObject,
    p2: GameObject,
    ball: GameObject,
    up: bool,
    down: bool,
    server: Player
}

enum Player {
    Left,
    Right
}

impl Pong {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

        let p1_rect = [0.0, 0.0, self.p1.size[0], self.p1.size[1]];
        let p2_rect = [0.0, 0.0, self.p2.size[0], self.p2.size[1]];
        let ball_rect = [0.0, 0.0, self.ball.size[0], self.ball.size[1]];
        let ball = &mut self.ball;
        let p1 = &mut self.p1;
        let p2 = &mut self.p2;

        self.gl.draw(args.viewport(), |c, gl| {
            clear(BLACK, gl);

            let transform = c.transform.trans(ball.pos[0], ball.pos[1])
                .trans(-ball.size[0]/2.0, -ball.size[1]/2.0);
            rectangle(WHITE, ball_rect, transform, gl);

            let transform = c.transform.trans(p1.pos[0], p1.pos[1])
                .trans(-p1.size[0]/2.0, -p1.size[1]/2.0);
            rectangle(WHITE, p1_rect, transform, gl);

            let transform = c.transform.trans(p2.pos[0], p2.pos[1])
                .trans(-p2.size[0]/2.0, -p2.size[1]/2.0);
            rectangle(WHITE, p2_rect, transform, gl);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        let (ai_up, ai_down) = self.handle_ai_paddle();

        Pong::handle_paddle(&mut self.p1, self.up, self.down, args.dt);
        Pong::handle_paddle(&mut self.p2, ai_up, ai_down, args.dt);
        Pong::handle_game_object(&mut self.p1, args.dt, false);
        Pong::handle_game_object(&mut self.p2, args.dt, false);
        Pong::handle_game_object(&mut self.ball, args.dt, true);
        self.handle_ball();
    }

    fn start(&mut self) {
        self.p1.pos = [self.p1.size[0] / 2.0 + 4.0, (SIZE[1] / 2) as f64];
        self.p2.pos = [SIZE[0] as f64 - self.p2.size[0] / 2.0 - 4.0,
            (SIZE[1] / 2) as f64];

        self.reset();
    }

    fn reset(&mut self) {
        use std::f64::consts::PI;
        use rand;
        use rand::Rng;

        self.ball.pos = [(SIZE[0] / 2) as f64, (SIZE[1] / 2) as f64];

        let mut rng = rand::thread_rng();
        let max_angle = 2.0 * BALL_START_MAX_ANGLE * PI / 180.0;
        let angle = rng.next_f64() * max_angle - max_angle / 2.0;
        self.ball.vel = [
            angle.cos() * BALL_START_SPEED * self.serve_direction(),
            angle.sin() * BALL_START_SPEED
        ];
    }

    fn serve_direction(&mut self) -> f64 {
        match self.server {
            Player::Left => { -1.0 }
            Player::Right => { 1.0 }
        }
    }

    fn key_press(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true; }
            Key::Down => { self.down = true; }
            _ => {}
        }
    }

    fn key_release(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false; }
            Key::Down => { self.down = false; }
            _ => {}
        }
    }

    fn handle_game_object(obj: &mut GameObject, dt: f64, bounce: bool) {
        obj.pos[0] += obj.vel[0] * dt;
        obj.pos[1] += obj.vel[1] * dt;

        if obj.pos[1] + obj.size[1] / 2.0 >= SIZE[1] as f64 {
            obj.pos[1] = SIZE[1] as f64 - obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }

        if obj.pos[1] - obj.size[1] / 2.0 <= 0.0f64 {
            obj.pos[1] = obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }
    }

    fn handle_paddle(paddle: &mut GameObject, up: bool, down: bool, dt: f64) {
        if up {
            paddle.vel[1] -= PADDLE_ACCEL * dt;
        } else if down {
            paddle.vel[1] += PADDLE_ACCEL * dt;
        } else {
            let dv = -paddle.vel[1].signum() * PADDLE_ACCEL * dt;

            if dv.abs() >= paddle.vel[1].abs() { paddle.vel[1] = 0.0; }
            else { paddle.vel[1] += dv; }
        }

        if paddle.vel[1] > PADDLE_MAX_SPEED {
            paddle.vel[1] = PADDLE_MAX_SPEED;
        } else if paddle.vel[1] < -PADDLE_MAX_SPEED {
            paddle.vel[1] = -PADDLE_MAX_SPEED;
        }
    }

    fn handle_ai_paddle(&self) -> (bool, bool) {
        let mut ai_up = false;
        let mut ai_down = false;

        if self.ball.vel[0] > 0.0 {
            let t = (self.p2.pos[0] - self.ball.pos[0]) / self.ball.vel[0];
            let target_y = self.ball.pos[1] + self.ball.vel[1] * t;

            if target_y > self.p2.pos[1] { ai_down = true; }
            else if target_y < self.p2.pos[1] { ai_up = true; }
        }

        (ai_up, ai_down)
    }

    fn handle_ball(&mut self) {
        for paddle in [&self.p1, &self.p2].iter() {
            match self.ball.collision_normal(paddle) {
                Some(normal) => {
                    let dot = self.ball.vel[0] * normal[0] +
                        self.ball.vel[1] * normal[1];

                    // reflect ball's velocity off collision normal
                    self.ball.vel = [
                        self.ball.vel[0] - 2.0 * normal[0] * dot,
                        self.ball.vel[1] - 2.0 * normal[1] * dot
                    ];

                    // apply a bit of paddle velocity to ball
                    if normal[0] != 0.0 {
                        self.ball.vel[1] += paddle.vel[1] * PADDLE_FRICTION;
                    }

                    Pong::correct_collision(&mut self.ball, paddle, normal);
                }

                None => {}
            }
        }

        if self.ball.pos[0] > SIZE[0] as f64 { self.score(Player::Left); }
        else if self.ball.pos[0] < 0.0 { self.score(Player::Right); }
    }

    fn correct_collision(a: &mut GameObject, b: &GameObject, normal: [f64; 2]) {
        if normal == [1.0, 0.0] {
            a.pos[0] = b.pos[0] + b.size[0] / 2.0 + a.size[0] / 2.0;
        } else if normal == [-1.0, 0.0] {
            a.pos[0] = b.pos[0] - b.size[0] / 2.0 - a.size[0] / 2.0;
        } else if normal == [0.0, 1.0] {
            a.pos[1] = b.pos[1] + b.size[1] / 2.0 + a.size[1] / 2.0;
        } else if normal == [0.0, -1.0] {
            a.pos[1] = b.pos[1] - b.size[1] / 2.0 - a.size[1] / 2.0;
        }
    }

    fn score(&mut self, player: Player) {
        match player {
            Player::Left => {
                self.server = Player::Right;
            }

            Player::Right => {
                self.server = Player::Left;
            }
        }

        self.reset();
    }
}

pub fn play() {

    let window = Window::new(OPENGL_VERSION,
        WindowSettings::new("pong", SIZE)
        .exit_on_esc(true));

    let mut pong = Pong {
        gl: GlGraphics::new(OPENGL_VERSION),
        p1: GameObject { size: PADDLE_SIZE, ..Default::default() },
        p2: GameObject { size: PADDLE_SIZE, ..Default::default() },
        ball: GameObject { size: BALL_SIZE, ..Default::default() },
        up: false,
        down: false,
        server: Player::Left
    };

    pong.start();

    for e in window.events() {
        if let Some(r) = e.render_args() { pong.render(&r); }
        if let Some(u) = e.update_args() { pong.update(&u); }
        if let Some(Keyboard(key)) = e.press_args() { pong.key_press(key); }
        if let Some(Keyboard(key)) = e.release_args() { pong.key_release(key); }
    }
}
<|endoftext|>