<commit_before>extern crate bindgen;
#[macro_use]
extern crate log;
extern crate docopt;
#[macro_use]
extern crate rustc_serialize;
extern crate env_logger;

use bindgen::{Builder, LinkType};
use std::io::{self, Write};
use std::fs::File;
use std::process::exit;

const USAGE: &'static str = "
Generate C bindings for Rust.

Usage:
  bindgen [options] <file> [-- <clang-args>...]
  bindgen (-h | --help)

Options:
  <clang-args>                 Options passed directly to clang.
  -h, --help                   Display this help message.
  --link=<library>             Link to a dynamic library, can be provided multiple times.
                               <library> is in the format `[kind=]lib`, where `kind` is
                               one of `static`, `dynamic` or `framework`.
  --output=<output>            Write bindings to <output> (- is stdout).
                               [default: -]
  --match=<name>               Only output bindings for definitions from files
                               whose name contains <name>
                               If multiple -match options are provided, files
                               matching any rule are bound to.
  --builtins                   Output bindings for builtin definitions
                               (for example __builtin_va_list)
  --emit-clang-ast             Output the ast (for debugging purposes)
  --override-enum-type=<type>  Override enum type, type name could be
                                 uchar
                                 schar
                                 ushort
                                 sshort
                                 uint
                                 sint
                                 ulong
                                 slong
                                 ulonglong
                                 slonglong
  --use-core                  Use `core` as a base crate for `Option` and such.
                              See also `--ctypes-prefix`.
  --ctypes-prefix=<prefix>    Use this prefix for all the types in the generated
                              code.
                              [default: std::os::raw]
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_file: String,
    arg_clang_args: Vec<String>,
    flag_link: String,
    flag_output: String,
    flag_match: Option<String>,
    flag_builtins: bool,
    flag_emit_clang_ast: bool,
    flag_override_enum_type: String,
    flag_ctypes_prefix: String,
    flag_use_core: bool,
}

fn args_to_opts(args: Args, builder: &mut Builder) {
    builder.header(args.arg_file)
           .emit_ast(args.flag_emit_clang_ast)
           .ctypes_prefix(args.flag_ctypes_prefix
                              .split("::")
                              .map(String::from)
                              .collect::<Vec<_>>())
           .use_core(args.flag_use_core)
           .override_enum_ty(args.flag_override_enum_type);
    for arg in args.arg_clang_args {
        builder.clang_arg(arg);
    }
    if let Some(s) = args.flag_match {
        builder.match_pat(s);
    }
    if args.flag_builtins {
        builder.builtins();
    }
    let mut parts = args.flag_link.split('=');
    let (lib, kind) = match (parts.next(), parts.next()) {
        (Some(lib), None) => (lib, LinkType::Dynamic),
        (Some(kind), Some(lib)) => {
            (lib,
             match kind {
                "static" => LinkType::Static,
                "dynamic" => LinkType::Dynamic,
                "framework" => LinkType::Framework,
                _ => {
                    println!("Link type unknown: {}", kind);
                    exit(1);
                }
            })
        }
        _ => {
            println!("Wrong link format: {}", args.flag_link);
            exit(1);
        }
    };
    builder.link(lib, kind);
}

fn get_output(o: &str) -> Box<Write> {
    if o == "-" {
        Box::new(io::stdout())
    } else {
        Box::new(File::open(o).expect(&format!("\"{}\" unreadable", o)))
    }
}

pub fn main() {
    env_logger::LogBuilder::new().parse("bindgen=warn").init().unwrap();

    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    debug!("{:?}", args);

    let output = get_output(&args.flag_output);

    let mut builder = Builder::new();
    args_to_opts(args, &mut builder);
    debug!("{:?}", builder);

    match builder.generate() {
        Ok(bindings) => {
            match bindings.write(output) {
                Ok(()) => (),
                Err(e) => {
                    error!("Unable to write bindings to file. {}", e);
                    exit(-1);
                }
            }
        }
        Err(()) => exit(-1),
    }
}
<commit_msg>Make link command line option optional<commit_after>extern crate bindgen;
#[macro_use]
extern crate log;
extern crate docopt;
#[macro_use]
extern crate rustc_serialize;
extern crate env_logger;

use bindgen::{Builder, LinkType};
use std::io::{self, Write};
use std::fs::File;
use std::process::exit;

const USAGE: &'static str = "
Generate C bindings for Rust.

Usage:
  bindgen [options] <file> [-- <clang-args>...]
  bindgen (-h | --help)

Options:
  <clang-args>                 Options passed directly to clang.
  -h, --help                   Display this help message.
  --link=<library>             Link to a dynamic library, can be provided multiple times.
                               <library> is in the format `[kind=]lib`, where `kind` is
                               one of `static`, `dynamic` or `framework`.
  --output=<output>            Write bindings to <output> (- is stdout).
                               [default: -]
  --match=<name>               Only output bindings for definitions from files
                               whose name contains <name>
                               If multiple -match options are provided, files
                               matching any rule are bound to.
  --builtins                   Output bindings for builtin definitions
                               (for example __builtin_va_list)
  --emit-clang-ast             Output the ast (for debugging purposes)
  --override-enum-type=<type>  Override enum type, type name could be
                                 uchar
                                 schar
                                 ushort
                                 sshort
                                 uint
                                 sint
                                 ulong
                                 slong
                                 ulonglong
                                 slonglong
  --use-core                  Use `core` as a base crate for `Option` and such.
                              See also `--ctypes-prefix`.
  --ctypes-prefix=<prefix>    Use this prefix for all the types in the generated
                              code.
                              [default: std::os::raw]
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_file: String,
    arg_clang_args: Vec<String>,
    flag_link: Option<String>,
    flag_output: String,
    flag_match: Option<String>,
    flag_builtins: bool,
    flag_emit_clang_ast: bool,
    flag_override_enum_type: String,
    flag_ctypes_prefix: String,
    flag_use_core: bool,
}

fn args_to_opts(args: Args, builder: &mut Builder) {
    builder.header(args.arg_file)
           .emit_ast(args.flag_emit_clang_ast)
           .ctypes_prefix(args.flag_ctypes_prefix
                              .split("::")
                              .map(String::from)
                              .collect::<Vec<_>>())
           .use_core(args.flag_use_core)
           .override_enum_ty(args.flag_override_enum_type);
    for arg in args.arg_clang_args {
        builder.clang_arg(arg);
    }
    if let Some(s) = args.flag_match {
        builder.match_pat(s);
    }
    if args.flag_builtins {
        builder.builtins();
    }
    if let Some(link) = args.flag_link {
        let mut parts = link.split('=');
        let (lib, kind) = match (parts.next(), parts.next()) {
            (Some(lib), None) => (lib, LinkType::Dynamic),
            (Some(kind), Some(lib)) => {
                (lib,
                 match kind {
                    "static" => LinkType::Static,
                    "dynamic" => LinkType::Dynamic,
                    "framework" => LinkType::Framework,
                    _ => {
                        println!("Link type unknown: {}", kind);
                        exit(1);
                    }
                })
            }
            _ => {
                println!("Wrong link format: {}", link);
                exit(1);
            }
        };
        builder.link(lib, kind);
    }
}

fn get_output(o: &str) -> Box<Write> {
    if o == "-" {
        Box::new(io::stdout())
    } else {
        Box::new(File::open(o).expect(&format!("\"{}\" unreadable", o)))
    }
}

pub fn main() {
    env_logger::LogBuilder::new().parse("bindgen=warn").init().unwrap();

    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    debug!("{:?}", args);

    let output = get_output(&args.flag_output);

    let mut builder = Builder::new();
    args_to_opts(args, &mut builder);
    debug!("{:?}", builder);

    match builder.generate() {
        Ok(bindings) => {
            match bindings.write(output) {
                Ok(()) => (),
                Err(e) => {
                    error!("Unable to write bindings to file. {}", e);
                    exit(-1);
                }
            }
        }
        Err(()) => exit(-1),
    }
}
<|endoftext|>


<commit_before>mod words;

mod sort;
use sort::{HeapPopDrain};

use std::env;
use std::collections::{BinaryHeap};

fn matches(pat: &String, line: &str) -> bool {
    fn check<P, L>(mut pc: P, lc: L) -> bool where P: Iterator<Item=char>, L: Iterator<Item=char> {
        let mut c = pc.next();
        for outer in lc {
            match c {
                Some(ch) => {
                    if outer == ch {
                        c = pc.next();
                    }
                    else if words::consonant(outer) {
                        return false;
                    }
                },

                None => {
                    return true;
                }
            }
        }

        c.is_none()
    }

    (pat.len() <= line.len()) && (
        check(pat.chars(), line.chars()) ||
        check(pat.chars().rev(), line.chars().rev())
    )
}

fn usage(args: Vec<String>) -> ! {
    println!("Usage: {} <consonants>", args[0]);
    std::process::exit(2);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        usage(args);
    }
    if args[1].chars().any(|c| {!words::consonant(c)}) {
        usage(args);
    }

    let words = words::WORDS.lines().map(|line| {
        line.to_lowercase()
    }).filter(|line| {
        matches(&args[1], line)
    });

    let mut found = BinaryHeap::new();
    for word in words {
        found.push(sort::Length(word));
    }
    if found.len() == 0 {
        println!("No matches found.");
        return;
    }

    for word in found.pop_drain() {
        println!("{}", word.0);
    }
}
<commit_msg>Switch back to a BTreeSet.<commit_after>mod words;

mod sort;

use std::env;
use std::collections::{BTreeSet};

fn matches(pat: &String, line: &str) -> bool {
    fn check<P, L>(mut pc: P, lc: L) -> bool where P: Iterator<Item=char>, L: Iterator<Item=char> {
        let mut c = pc.next();
        for outer in lc {
            match c {
                Some(ch) => {
                    if outer == ch {
                        c = pc.next();
                    }
                    else if words::consonant(outer) {
                        return false;
                    }
                },

                None => {
                    return true;
                }
            }
        }

        c.is_none()
    }

    (pat.len() <= line.len()) && (
        check(pat.chars(), line.chars()) ||
        check(pat.chars().rev(), line.chars().rev())
    )
}

fn usage(args: Vec<String>) -> ! {
    println!("Usage: {} <consonants>", args[0]);
    std::process::exit(2);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        usage(args);
    }
    if args[1].chars().any(|c| {!words::consonant(c)}) {
        usage(args);
    }

    let words = words::WORDS.lines().map(|line| {
        line.to_lowercase()
    }).filter(|line| {
        matches(&args[1], line)
    });

    let mut found = BTreeSet::new();
    for word in words {
        found.insert(sort::Length(word));
    }
    if found.len() == 0 {
        println!("No matches found.");
        return;
    }

    for word in found.iter().rev() {
        println!("{}", word.0);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        _ => l,
    }
}

fn map_mut_ty(mut_ty: &MutTy) -> String {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

fn map_return_type(ret: &FunctionRetTy) -> String {
    match ret {
        &FunctionRetTy::Default => "void".to_string(),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, ..) => {
                if has_no_mangle(&item.attrs) {
                    println!("WR_INLINE {}\n{}({})\nWR_FUNC;\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "));
                }
            }
            _ => {}
        }
    }

}
<commit_msg>Ensure the function uses a C ABI<commit_after>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        _ => l,
    }
}

fn map_mut_ty(mut_ty: &MutTy) -> String {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

fn map_return_type(ret: &FunctionRetTy) -> String {
    match ret {
        &FunctionRetTy::Default => "void".to_string(),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, _unsafe, _const, abi, _generic, _block) => {
                if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                    println!("WR_INLINE {}\n{}({})\nWR_FUNC;\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "));
                }
            }
            _ => {}
        }
    }

}
<|endoftext|>


<commit_before>fn problem1a() {
    let mut sum = 0;
    for n in 1..1000 {
        if n % 3 == 0 || n % 5 == 0 {
            sum += n
        }
    }
    println!("{}", sum);
}

fn problem1b() {
    println!("{}", (1..1000)
            .filter(|n| n % 3 == 0 || n % 5 == 0)
            .fold(0, |sum, i| sum + i)
    );
}

fn problem1c() {
   println!("{}",
       (1..1000)
        .fold(0, |sum, i| {
                if i % 3 == 0 || i % 5 == 0 { sum + i } else { sum }
            }
       )
   );
}

fn main() {
    problem1a();
    problem1b();
    problem1c();
}
<commit_msg>project euler problem 2<commit_after>fn problem1a() {
    let mut sum = 0;
    for n in 1..1000 {
        if n % 3 == 0 || n % 5 == 0 {
            sum += n
        }
    }
    println!("{}", sum);
}

fn problem1b() {
    println!("{}", (1..1000)
            .filter(|n| n % 3 == 0 || n % 5 == 0)
            .fold(0, |sum, i| sum + i)
    );
}

fn problem1c() {
   println!("{}",
       (1..1000)
        .fold(0, |sum, i| {
                if i % 3 == 0 || i % 5 == 0 { sum + i } else { sum }
            }
       )
   );
}

struct Fib {
   curr: u32,
   next: u32
}

impl Iterator for Fib {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        let new = self.curr + self.next;

        self.curr = self.next;
        self.next = new;

        Some(self.curr)
    }
}

fn euler2() {
    let fib = Fib {curr: 1, next: 1};
    println!("{}", fib
            .take_while(|&a| a < 4_000_000)
            .filter(|&a| a % 2 == 0)
            .fold(0, |sum, i| sum + i));
}

fn main() {
    problem1a();
    problem1b();
    problem1c();
    euler2();
}
<|endoftext|>


<commit_before>const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");

static FORMAT: &'static str = "{request-time}: {method} {uri} {status} {response-time}";

#[macro_use]
extern crate clap;
use clap::{Arg, ArgMatches, App, AppSettings, SubCommand};

extern crate toml;
extern crate rustc_serialize;
extern crate regex;

extern crate iron;
use iron::prelude::*;
use iron::Handler;
use iron::method::Method;
use std::str::FromStr;

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::{SimpleLogger, LogLevelFilter};

extern crate logger;
use logger::Logger;
use logger::Format;

extern crate notify;

use notify::{RecommendedWatcher, Watcher, RecursiveMode};
use notify::DebouncedEvent::{Create, Write};
use std::sync::mpsc::{channel, Receiver};
use std::time::Duration;

use std::thread;

mod config;
use config::{Config, ServerConfig, RequestConfig, ResponseConfig};
use std::collections::HashMap;
use std::ascii::AsciiExt;
mod error;
use error::HaxoniteError;
mod handlers;
use handlers::*;
mod utils;

use std::path::Path;

fn main() {
    let _ = SimpleLogger::init(LogLevelFilter::Info, simplelog::Config::default());

    match run() {
        Ok(_) => {}
        Err(err) => {
            error!("{}!", err);
            std::process::exit(-1);
        }
    }
}

fn run() -> Result<(), HaxoniteError> {
    let matches = define_command_line_options().get_matches();
    if let Some(matches) = matches.subcommand_matches("new") {
        let generate_full_project = matches.is_present("full");
        if let Some(project_name) = matches.value_of("project_name") {
            try!(utils::create_new_project(project_name, generate_full_project));
        }
        return Ok(());
    }

    if let Some(matches) = matches.subcommand_matches("serve") {
        try!(serve(matches, None));
    }
    if let Some(matches) = matches.subcommand_matches("watch") {
        try!(watch(matches));
    }
    Ok(())
}

fn serve(matches: &ArgMatches, rx_server: Option<Receiver<&str>>) -> Result<(), HaxoniteError> {
    let config_file = matches.value_of("config_file").unwrap_or("config.toml");
    loop {
        let config_content = try!(config::read_config(config_file));
        let config: Config = toml::decode_str(config_content.as_ref()).unwrap(); // TODO: remove unwrap to handle malformed config
        debug!("Using config: {:?}!", config);

        let server_config = config.server.unwrap_or_else(ServerConfig::default);
        let host = match value_t!(matches, "host", String) { // TODO: rewrite these matches
            Ok(host) => host,
            Err(_) => server_config.host.unwrap_or_else(config::default_host),
        };
        let port_number = match value_t!(matches, "port_number", u16) {
            Ok(port_number) => port_number,
            Err(_) => server_config.port.unwrap_or_else(config::default_port),
        };

        // Initialize Iron's router and pass it to config processing function to define routes
        let mut router = Router::new();
        let mut mount = Mount::new();
        match config.requests {
            Some(requests) => {
                try!(process_config_requests(&requests, &mut mount, &mut router));
            }
            None => return Err(HaxoniteError::NoRequestDefined),
        }
        mount.mount("/", router);

        // Insert logger middlewares before and after router
        let mut chain = Chain::new(mount);
        let format = Format::new(FORMAT);
        let (logger_before, logger_after) = Logger::new(Some(format.unwrap()));
        chain.link_before(logger_before);
        chain.link_after(logger_after);

        // Initialize Iron to process requests
        let mut _iron = try!(Iron::new(chain).http((host.as_ref(), port_number)));
        info!("Haxonite running on port: {}!", port_number);

        if let Some(ref rx_server) = rx_server {
            match rx_server.recv() {
                Ok(_) => {
                    _iron.close().expect("Iron cannot be closed");
                    thread::sleep(Duration::from_secs(1));
                    continue
                },
                Err(_) => break
            }
        }
    }
    Ok(())
}

fn watch(matches: &ArgMatches) -> Result<(), HaxoniteError> {
    let config_file = matches.value_of("config_file").unwrap_or("config.toml");

    let (tx_watcher, rx_watcher) = channel();
    let (tx_server, rx_server) = channel();

    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx_watcher, Duration::from_secs(1)));
    try!(watcher.watch(config_file, RecursiveMode::NonRecursive)); // NonRecursie as we only watch config file
    thread::spawn(move || {
        loop {
            match rx_watcher.recv() {
                Ok(event) => {
                    match event {
                        Create(_) | Write(_) => tx_server.send("reload").unwrap(), // reload only on file save or create
                        _ => continue
                    }
                },
                Err(e) => error!("watch error: {:?}", e),
            }
        }
    });
    serve(matches, Some(rx_server))
}

fn process_config_requests(requests: &HashMap<String, RequestConfig>,
                           mut mount: &mut Mount,
                           mut router: &mut Router)
                           -> Result<(), HaxoniteError> {
    info!("Processing config!");
    for (request_name, request_config) in requests {
        info!("Processing config for {}: {:?}!",
              request_name,
              request_config);
        try!(define_route(request_name.clone(),
                          request_config.clone(),
                          &mut mount,
                          &mut router));
    }
    Ok(())
}

fn define_route(request_name: String, request_config: RequestConfig, mount: &mut Mount, router: &mut Router) -> Result<(), HaxoniteError> {
    let method = request_config.method.unwrap_or_else(config::default_method);
    let path = match request_config.path {
        Some(path) => path,
        None => return Err(HaxoniteError::NoPathDefined(request_name.clone())),
    };

    let type_ = request_config.type_.unwrap_or_else(config::default_type);
    let response_configs = match request_config.responses {
        Some(response_configs) => response_configs,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    let handler: Box<Handler> = match type_.as_ref() {
        "single" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            Box::new(try!(get_single_response_handler(request_name.clone(), response_config.clone())))
        }
        "random" => {
            let mut handler = RandomResponse::new();
            for response_config in &response_configs {
                let weight = response_config.weight.unwrap_or_else(config::default_weight);
                handler.add_handler(weight,
                                    try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "roundrobin" => {
            let mut handler = IteratingResponse::new("roundrobin");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "chain" => {
            let mut handler = IteratingResponse::new("chain");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "static" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            let response = match response_config.response {
                Some(ref response) => response,
                None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
            };
            let handler = Static::new(Path::new(&response));
            Box::new(handler)
        }
        _ => return Err(HaxoniteError::InvalidType(request_name.clone())),
    };

    match Method::from_str(method.to_ascii_uppercase().as_ref()) {
        Ok(Method::Extension(_)) |
        Err(_) => return Err(HaxoniteError::InvalidHTTPMethod(request_name.clone())),
        Ok(a) => {
            match type_.as_ref() {
                "static" => {
                    info!("Mounting static for: {} using {} type of handler.\n",
                          path,
                          type_);
                    mount.mount(path.as_ref(), handler);
                }
                _ => {
                    info!("Defining route for: {} using {} type of handler.\n",
                          path,
                          type_);
                    router.route(a, path.clone(), handler, request_name);
                }
            }
        }
    };
    Ok(())
}

fn get_single_response_handler(request_name: String, response_config: ResponseConfig) -> Result<SingleResponse, HaxoniteError> {
    let headers = process_headers(response_config.headers);
    let status = match response_config.status {
        Some(status) if status >= 100 && status <= 599 => status, // switch to Range's contains() when it will be stable
        Some(status) => return Err(HaxoniteError::InvalidHTTPStatus(request_name.clone(), status)),
        None => config::default_status(),
    };
    let response = match response_config.response {
        Some(response) => response,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    if !Path::new(&response).exists() {
        return Err(HaxoniteError::ResponseDoesNotExist(request_name.clone()));
    }
    Ok(SingleResponse::new(status, headers, response, response_config.delay))
}

fn process_headers(headers: Option<Vec<String>>) -> Vec<Vec<String>> {
    // TODO: This method should be optimized to not compile regex on every run,
    // not match on header when the default is used (it's valid)
    use regex::Regex;
    let re = Regex::new(r"([\w-]+):\s+([\w/]+)").unwrap();

    let headers = headers.unwrap_or_else(config::default_headers);
    headers.iter()
        .filter(|header| {
            if re.is_match(header) {
                true
            } else {
                warn!("Header {} is invalid (does not match \": \"). Skipping.",
                      header);
                false
            }
        })
        .map(|header| {
            header.split(": ")
                .map(// TODO: This is quite stupid and could be done with &str,
                     // but I decided to use String to not fight borrow checker for now...
                     |hdr| hdr.to_string())
                .collect()
        })
        .collect()
}

fn define_command_line_options<'a, 'b>() -> App<'a, 'b> {
    App::new("Haxonite")
        .setting(AppSettings::SubcommandRequired)
        .version(VERSION)
        .author(AUTHORS)
        .about("Easy API mocking")
        .subcommand(SubCommand::with_name("serve")
            .about("Starts Haxonite server")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("watch")
            .about("Starts Haxonite server with dynamic reload on change")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("new")
            .about("Create new Haxonite project")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("full")
                .help("Use to create a project with full config.toml file")
                .short("f")
                .long("full"))
            .arg(Arg::with_name("project_name")
                .help("Name of the project (will be used as a directory name)")
                .index(1)
                .required(true)))
}
<commit_msg>#6: Get rid of a redundant thread & channel<commit_after>const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");

static FORMAT: &'static str = "{request-time}: {method} {uri} {status} {response-time}";

#[macro_use]
extern crate clap;
use clap::{Arg, ArgMatches, App, AppSettings, SubCommand};

extern crate toml;
extern crate rustc_serialize;
extern crate regex;

extern crate iron;
use iron::prelude::*;
use iron::Handler;
use iron::method::Method;
use std::str::FromStr;

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::{SimpleLogger, LogLevelFilter};

extern crate logger;
use logger::Logger;
use logger::Format;

extern crate notify;

use notify::{RecommendedWatcher, Watcher, RecursiveMode};
use notify::DebouncedEvent;
use notify::DebouncedEvent::{Create, Write};
use std::sync::mpsc::{channel, Receiver};
use std::time::Duration;

use std::thread;

mod config;
use config::{Config, ServerConfig, RequestConfig, ResponseConfig};
use std::collections::HashMap;
use std::ascii::AsciiExt;
mod error;
use error::HaxoniteError;
mod handlers;
use handlers::*;
mod utils;

use std::path::Path;

fn main() {
    let _ = SimpleLogger::init(LogLevelFilter::Info, simplelog::Config::default());

    match run() {
        Ok(_) => {}
        Err(err) => {
            error!("{}!", err);
            std::process::exit(-1);
        }
    }
}

fn run() -> Result<(), HaxoniteError> {
    let matches = define_command_line_options().get_matches();
    if let Some(matches) = matches.subcommand_matches("new") {
        let generate_full_project = matches.is_present("full");
        if let Some(project_name) = matches.value_of("project_name") {
            try!(utils::create_new_project(project_name, generate_full_project));
        }
        return Ok(());
    }

    if let Some(matches) = matches.subcommand_matches("serve") {
        try!(serve(matches, None));
    }
    if let Some(matches) = matches.subcommand_matches("watch") {
        try!(watch(matches));
    }
    Ok(())
}

fn serve(matches: &ArgMatches, rx_watcher: Option<Receiver<DebouncedEvent>>) -> Result<(), HaxoniteError> {
    let config_file = matches.value_of("config_file").unwrap_or("config.toml");
    'serve: loop {
        let config_content = try!(config::read_config(config_file));
        let config: Config = toml::decode_str(config_content.as_ref()).unwrap(); // TODO: remove unwrap to handle malformed config
        debug!("Using config: {:?}!", config);

        let server_config = config.server.unwrap_or_else(ServerConfig::default);
        let host = match value_t!(matches, "host", String) { // TODO: rewrite these matches
            Ok(host) => host,
            Err(_) => server_config.host.unwrap_or_else(config::default_host),
        };
        let port_number = match value_t!(matches, "port_number", u16) {
            Ok(port_number) => port_number,
            Err(_) => server_config.port.unwrap_or_else(config::default_port),
        };

        // Initialize Iron's router and pass it to config processing function to define routes
        let mut router = Router::new();
        let mut mount = Mount::new();
        match config.requests {
            Some(requests) => {
                try!(process_config_requests(&requests, &mut mount, &mut router));
            }
            None => return Err(HaxoniteError::NoRequestDefined),
        }
        mount.mount("/", router);

        // Insert logger middlewares before and after router
        let mut chain = Chain::new(mount);
        let format = Format::new(FORMAT);
        let (logger_before, logger_after) = Logger::new(Some(format.unwrap()));
        chain.link_before(logger_before);
        chain.link_after(logger_after);

        // Initialize Iron to process requests
        let mut _iron = try!(Iron::new(chain).http((host.as_ref(), port_number)));
        info!("Haxonite running on port: {}!", port_number);

        if let Some(ref rx_watcher) = rx_watcher {
            'watch: loop {
                info!("Waiting for event to be received!");
                match rx_watcher.recv() {
                    Ok(event) => {
                        info!("Event: {:?}", event);
                        match event {
                            Create(_) | Write(_) => {
                                _iron.close().expect("Iron cannot be closed");
                                thread::sleep(Duration::from_secs(1));
                                break 'watch
                            },
                            _ => continue 'watch
                        }
                    },
                    Err(e) => error!("watch error: {:?}", e),
                }
            }
        }
    }
}

fn watch(matches: &ArgMatches) -> Result<(), HaxoniteError> {
    let config_file = matches.value_of("config_file").unwrap_or("config.toml");

    let (tx_watcher, rx_watcher) = channel();
    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx_watcher, Duration::from_secs(1)));
    try!(watcher.watch(config_file, RecursiveMode::NonRecursive)); // NonRecursie as we only watch config file

    serve(matches, Some(rx_watcher))
}

fn process_config_requests(requests: &HashMap<String, RequestConfig>,
                           mut mount: &mut Mount,
                           mut router: &mut Router)
                           -> Result<(), HaxoniteError> {
    info!("Processing config!");
    for (request_name, request_config) in requests {
        info!("Processing config for {}: {:?}!",
              request_name,
              request_config);
        try!(define_route(request_name.clone(),
                          request_config.clone(),
                          &mut mount,
                          &mut router));
    }
    Ok(())
}

fn define_route(request_name: String, request_config: RequestConfig, mount: &mut Mount, router: &mut Router) -> Result<(), HaxoniteError> {
    let method = request_config.method.unwrap_or_else(config::default_method);
    let path = match request_config.path {
        Some(path) => path,
        None => return Err(HaxoniteError::NoPathDefined(request_name.clone())),
    };

    let type_ = request_config.type_.unwrap_or_else(config::default_type);
    let response_configs = match request_config.responses {
        Some(response_configs) => response_configs,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    let handler: Box<Handler> = match type_.as_ref() {
        "single" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            Box::new(try!(get_single_response_handler(request_name.clone(), response_config.clone())))
        }
        "random" => {
            let mut handler = RandomResponse::new();
            for response_config in &response_configs {
                let weight = response_config.weight.unwrap_or_else(config::default_weight);
                handler.add_handler(weight,
                                    try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "roundrobin" => {
            let mut handler = IteratingResponse::new("roundrobin");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "chain" => {
            let mut handler = IteratingResponse::new("chain");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "static" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            let response = match response_config.response {
                Some(ref response) => response,
                None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
            };
            let handler = Static::new(Path::new(&response));
            Box::new(handler)
        }
        _ => return Err(HaxoniteError::InvalidType(request_name.clone())),
    };

    match Method::from_str(method.to_ascii_uppercase().as_ref()) {
        Ok(Method::Extension(_)) |
        Err(_) => return Err(HaxoniteError::InvalidHTTPMethod(request_name.clone())),
        Ok(a) => {
            match type_.as_ref() {
                "static" => {
                    info!("Mounting static for: {} using {} type of handler.",
                          path,
                          type_);
                    mount.mount(path.as_ref(), handler);
                }
                _ => {
                    info!("Defining route for: {} using {} type of handler.",
                          path,
                          type_);
                    router.route(a, path.clone(), handler, request_name);
                }
            }
        }
    };
    Ok(())
}

fn get_single_response_handler(request_name: String, response_config: ResponseConfig) -> Result<SingleResponse, HaxoniteError> {
    let headers = process_headers(response_config.headers);
    let status = match response_config.status {
        Some(status) if status >= 100 && status <= 599 => status, // switch to Range's contains() when it will be stable
        Some(status) => return Err(HaxoniteError::InvalidHTTPStatus(request_name.clone(), status)),
        None => config::default_status(),
    };
    let response = match response_config.response {
        Some(response) => response,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    if !Path::new(&response).exists() {
        return Err(HaxoniteError::ResponseDoesNotExist(request_name.clone()));
    }
    Ok(SingleResponse::new(status, headers, response, response_config.delay))
}

fn process_headers(headers: Option<Vec<String>>) -> Vec<Vec<String>> {
    // TODO: This method should be optimized to not compile regex on every run,
    // not match on header when the default is used (it's valid)
    use regex::Regex;
    let re = Regex::new(r"([\w-]+):\s+([\w/]+)").unwrap();

    let headers = headers.unwrap_or_else(config::default_headers);
    headers.iter()
        .filter(|header| {
            if re.is_match(header) {
                true
            } else {
                warn!("Header {} is invalid (does not match \": \"). Skipping.",
                      header);
                false
            }
        })
        .map(|header| {
            header.split(": ")
                .map(// TODO: This is quite stupid and could be done with &str,
                     // but I decided to use String to not fight borrow checker for now...
                     |hdr| hdr.to_string())
                .collect()
        })
        .collect()
}

fn define_command_line_options<'a, 'b>() -> App<'a, 'b> {
    App::new("Haxonite")
        .setting(AppSettings::SubcommandRequired)
        .version(VERSION)
        .author(AUTHORS)
        .about("Easy API mocking")
        .subcommand(SubCommand::with_name("serve")
            .about("Starts Haxonite server")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("watch")
            .about("Starts Haxonite server with dynamic reload on change")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("new")
            .about("Create new Haxonite project")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("full")
                .help("Use to create a project with full config.toml file")
                .short("f")
                .long("full"))
            .arg(Arg::with_name("project_name")
                .help("Name of the project (will be used as a directory name)")
                .index(1)
                .required(true)))
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]

#[macro_use]
extern crate lazy_static;
extern crate unicode_xid;

use std::{env, fmt, error, result};
use std::fs::File;
use std::io::Read;
use std::path::Path;

const EXIT_FAILURE: i32 = 1;

pub mod implicit_parse; // synthesized by LALRPOP

mod tok;
mod common;
mod implicit;
mod explicit;

use tok::Tokenizer;

// from https://stackoverflow.com/questions/27588416/how-to-send-output-to-stderr
macro_rules! eprintln(
    ($($arg:tt)*) => { {
	    use std::io::Write;
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

macro_rules! die(
    ($($arg:tt)*) => { {
	    eprintln!($($arg)*);
	    std::process::exit(EXIT_FAILURE)
    } }
);

fn usage() -> ! {
    let argv0 = env::args().nth(0).unwrap_or("<mdl>".to_string());
    die!("Usage: {} [OPTION...] PATH\n\
          Type inference.\n\
          \n\
          Options:\n\
            -help:\tshow this message",
         argv0);
}

macro_rules! err(
    ($($arg:tt)*) => { {
	Err(LiquidError{msg: format!($($arg)*)})
    } }
);

fn parse_args() -> String {

    for arg in env::args().skip(1) {
        if arg == "-help" {
            usage();
        } else if arg.chars().nth(0).unwrap_or(' ') == '-' {
            eprintln!("unknown arg '{}'", arg);
            usage();
        } else {
            return arg;
        }
    }
    // no args? die
    usage();
}

#[derive(Debug)]
pub struct LiquidError {
    msg: String,
}

impl fmt::Display for LiquidError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg)
    }
}

impl error::Error for LiquidError {
    fn description(&self) -> &str {
        &self.msg
    }
}

pub type Result<T> = result::Result<T, LiquidError>;

pub fn implicit_open<'a>(path: &Path) -> Result<Box<implicit::Exp>> {

    let mut file = match File::open(path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => {
            return err!("open({}): {}",
                        path.display(),
                        error::Error::description(&why))
        }
        Ok(file) => file,
    };

    let s = {
        let mut s = String::new();
        match file.read_to_string(&mut s) {
            Err(why) => {
                return err!("read({}): {}",
                            path.display(),
                            error::Error::description(&why))
            }
            Ok(_) => {}
        }
        s
    };

    let tokenizer = Tokenizer::new(&s);
    match implicit_parse::parse_Program(&s, tokenizer) {
        Ok(v) => Ok(v),
        Err(e) => err!("parse_Program: {:?}", e),
    }
}

struct MVEnv<'a> {
    env_id: &'a str,
    next_id: i32,
}

impl<'a> MVEnv<'a> {
    fn new(env: &'a str) -> MVEnv<'a> {
        MVEnv{env_id: env, next_id: 1}
    }

    fn alloc(&mut self, s: &String) -> explicit::Typ {
        let id = self.next_id;
        self.next_id += 1;
        explicit::Typ::TMetavar((id, s.clone()))
    }

    fn alloc_empty(&mut self) -> explicit::Typ {
        let id = self.next_id;
        self.next_id += 1;
        explicit::Typ::TMetavar((id, String::from(self.env_id)))
    }
}

fn add_metavars_in(env: &mut MVEnv, exp: &implicit::Exp) -> explicit::Exp {
    use implicit::Exp as I;
    use explicit::Exp as E;

    match *exp {
        I::Var(ref id) => {
            E::Var(id.clone())
        },
        I::Const(ref c) => E::Const(*c),
        I::Op2(ref op, ref l, ref r) => {
            let el = box add_metavars_in(env, l);
            let er = box add_metavars_in(env, r);
            E::Op2(*op, el, er)
        },
        I::Fun(ref id, ref e) => {
            let ee = box add_metavars_in(env, e);
            let mv = env.alloc(id);
            E::Fun(id.clone(), mv, ee)
        },
        I::App(ref e1, ref e2) => {
            let ee1 = box add_metavars_in(env, e1);
            let ee2 = box add_metavars_in(env, e2);
            E::App(ee1, ee2)
        },
        I::If(ref e1, ref e2, ref e3) => {
            let ee1 = box add_metavars_in(env, e1);
            let ee2 = box add_metavars_in(env, e2);
            let ee3 = box add_metavars_in(env, e3);
            E::If(ee1, ee2, ee3)
        },
        I::Let(ref id, ref e1, ref e2) => {
            let ee1 = box add_metavars_in(env, e1);
            let ee2 = box add_metavars_in(env, e2);
            E::Let(id.clone(), ee1, ee2)
        },
        I::Fix(ref id, ref e) => {
            let ee = box add_metavars_in(env, e);
            let mv = env.alloc(id);
            E::Fix(id.clone(), mv, ee)
        },
        I::Empty => {
            E::Empty(env.alloc_empty())
        },
        I::Cons(ref hd, ref tl) => {
            let ehd = box add_metavars_in(env, hd);
            let etl = box add_metavars_in(env, tl);
            E::Cons(ehd, etl)
        },
        I::Head(ref e) => {
            E::Head(box add_metavars_in(env, e))
        },
        I::Tail(ref e) => {
            E::Tail(box add_metavars_in(env, e))
        },
        I::IsEmpty(ref e) => {
            E::IsEmpty(box add_metavars_in(env, e))
        },
        I::Pair(ref l, ref r) => {
            let el = box add_metavars_in(env, l);
            let er = box add_metavars_in(env, r);
            E::Pair(el, er)
        },
        I::ProjL(ref e) => {
            E::ProjL(box add_metavars_in(env, e))
        },
        I::ProjR(ref e) => {
            E::ProjR(box add_metavars_in(env, e))
        },
    }
}

fn add_metavars(exp: &implicit::Exp) -> Box<explicit::Exp> {
    let mut env = MVEnv::new("α");
    box add_metavars_in(&mut env, exp)
}

fn main() {

    let path_s = parse_args();
    let path = Path::new(&path_s);

    // let fd = open(&path);

    // let state = make_state(fd);

    let exp = match implicit_open(&path) {
        Ok(v) => v,
        Err(e) => die!("implicit_open: {}", error::Error::description(&e)),
    };

    let typed_w_metavars = add_metavars(&exp);

    // α β

    // let m = make_machine(&asm);

    // let s = p.main().sim();

    // match s.run_to_end() {
    // 	Ok(_) =>
    //     Err()
    // }

    println!("result:\n\n{:?}", exp);
    println!("typed :\n\n{:?}", typed_w_metavars);
}

macro_rules! test_parse(
    ($s:expr) => { {
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        if let Err(e) = implicit_parse::parse_Program(&s, tokenizer) {
            die!("parse_Program({}): {:?}", $s, e)
        }
    } }
);

macro_rules! test_parse_fails(
    ($s:expr) => { {
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        if let Ok(_) = implicit_parse::parse_Program(&s, tokenizer) {
            die!("parse_Program({}) should have failed", $s)
        }
    } }
);

#[test]
fn implicit_parse() {
    test_parse!("-22");
    test_parse!("(22)");
    test_parse!("((((-22))))");
    test_parse!("((((-22))))");

    test_parse!("1 :: 2 :: empty");
    test_parse!("true :: false :: empty");
    test_parse!("true :: true :: empty");
    test_parse!("(2 + 3 - 2) + 3");
    test_parse!("fun x -> x + 1");
    test_parse!("let inc = fun x -> x + 1 in inc 3");
    test_parse!("let factorial = fix fac -> fun n -> if n = 0 then 1 else n * (fac (n - 1)) in factorial 5");
    test_parse!("let b = true in if b then true else false");
    test_parse!("let double = fun x -> x * 2 in double 3");
    test_parse!("let h = (fun l -> head l) in let l = 1 :: 2 :: empty in (h l) :: l");

    test_parse_fails!("((22)");
    test_parse_fails!("let x = 1"); // only let-in supported
}
<commit_msg>main: work on constraint generation<commit_after>#![feature(box_syntax)]

#[macro_use]
extern crate lazy_static;
extern crate unicode_xid;

use std::{env, fmt, error, result};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::collections::HashMap;

const EXIT_FAILURE: i32 = 1;

pub mod implicit_parse; // synthesized by LALRPOP

mod tok;
mod common;
mod implicit;
mod explicit;

use tok::Tokenizer;
use explicit::Typ;

// from https://stackoverflow.com/questions/27588416/how-to-send-output-to-stderr
macro_rules! eprintln(
    ($($arg:tt)*) => { {
	    use std::io::Write;
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

macro_rules! die(
    ($($arg:tt)*) => { {
	    eprintln!($($arg)*);
	    std::process::exit(EXIT_FAILURE)
    } }
);

fn usage() -> ! {
    let argv0 = env::args().nth(0).unwrap_or("<mdl>".to_string());
    die!("Usage: {} [OPTION...] PATH\n\
          Type inference.\n\
          \n\
          Options:\n\
            -help:\tshow this message",
         argv0);
}

macro_rules! err(
    ($($arg:tt)*) => { {
	Err(LiquidError{msg: format!($($arg)*)})
    } }
);

fn parse_args() -> String {

    for arg in env::args().skip(1) {
        if arg == "-help" {
            usage();
        } else if arg.chars().nth(0).unwrap_or(' ') == '-' {
            eprintln!("unknown arg '{}'", arg);
            usage();
        } else {
            return arg;
        }
    }
    // no args? die
    usage();
}

#[derive(Debug)]
pub struct LiquidError {
    msg: String,
}

impl fmt::Display for LiquidError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg)
    }
}

impl error::Error for LiquidError {
    fn description(&self) -> &str {
        &self.msg
    }
}

pub type Result<T> = result::Result<T, LiquidError>;

pub fn implicit_open<'a>(path: &Path) -> Result<Box<implicit::Exp>> {

    let mut file = match File::open(path) {
        // The `description` method of `io::Error` returns a string that
        // describes the error
        Err(why) => {
            return err!("open({}): {}",
                        path.display(),
                        error::Error::description(&why))
        }
        Ok(file) => file,
    };

    let s = {
        let mut s = String::new();
        match file.read_to_string(&mut s) {
            Err(why) => {
                return err!("read({}): {}",
                            path.display(),
                            error::Error::description(&why))
            }
            Ok(_) => {}
        }
        s
    };

    let tokenizer = Tokenizer::new(&s);
    match implicit_parse::parse_Program(&s, tokenizer) {
        Ok(v) => Ok(v),
        Err(e) => err!("parse_Program: {:?}", e),
    }
}

struct MVEnv<'a> {
    env_id: &'a str,
    next_id: i32,
}

impl<'a> MVEnv<'a> {
    fn new(env: &'a str) -> MVEnv<'a> {
        MVEnv {
            env_id: env,
            next_id: 1,
        }
    }

    fn alloc(&mut self, s: &String) -> Typ {
        let id = self.next_id;
        self.next_id += 1;
        Typ::TMetavar((id, s.clone()))
    }

    fn alloc_empty(&mut self) -> Typ {
        let id = self.next_id;
        self.next_id += 1;
        Typ::TMetavar((id, String::from(self.env_id)))
    }
}

fn add_metavars_in(env: &mut MVEnv, exp: &implicit::Exp) -> explicit::Exp {
    use implicit::Exp as I;
    use explicit::Exp as E;

    match *exp {
        I::Var(ref id) => E::Var(id.clone()),
        I::Const(ref c) => E::Const(*c),
        I::Op2(ref op, ref l, ref r) => {
            let el = box add_metavars_in(env, l);
            let er = box add_metavars_in(env, r);
            E::Op2(*op, el, er)
        }
        I::Fun(ref id, ref e) => {
            let ee = box add_metavars_in(env, e);
            let mv = env.alloc(id);
            E::Fun(id.clone(), mv, ee)
        }
        I::App(ref e1, ref e2) => {
            let ee1 = box add_metavars_in(env, e1);
            let ee2 = box add_metavars_in(env, e2);
            E::App(ee1, ee2)
        }
        I::If(ref e1, ref e2, ref e3) => {
            let ee1 = box add_metavars_in(env, e1);
            let ee2 = box add_metavars_in(env, e2);
            let ee3 = box add_metavars_in(env, e3);
            E::If(ee1, ee2, ee3)
        }
        I::Let(ref id, ref e1, ref e2) => {
            let ee1 = box add_metavars_in(env, e1);
            let ee2 = box add_metavars_in(env, e2);
            E::Let(id.clone(), ee1, ee2)
        }
        I::Fix(ref id, ref e) => {
            let ee = box add_metavars_in(env, e);
            let mv = env.alloc(id);
            E::Fix(id.clone(), mv, ee)
        }
        I::Empty => E::Empty(env.alloc_empty()),
        I::Cons(ref hd, ref tl) => {
            let ehd = box add_metavars_in(env, hd);
            let etl = box add_metavars_in(env, tl);
            E::Cons(ehd, etl)
        }
        I::Head(ref e) => E::Head(box add_metavars_in(env, e)),
        I::Tail(ref e) => E::Tail(box add_metavars_in(env, e)),
        I::IsEmpty(ref e) => E::IsEmpty(box add_metavars_in(env, e)),
        I::Pair(ref l, ref r) => {
            let el = box add_metavars_in(env, l);
            let er = box add_metavars_in(env, r);
            E::Pair(el, er)
        }
        I::ProjL(ref e) => E::ProjL(box add_metavars_in(env, e)),
        I::ProjR(ref e) => E::ProjR(box add_metavars_in(env, e)),
    }
}

fn add_metavars(exp: &implicit::Exp) -> Box<explicit::Exp> {
    let mut env = MVEnv::new("α");
    box add_metavars_in(&mut env, exp)
}

fn gen_constraints(m: &mut MVEnv,
                   env: &mut HashMap<&str, &str>,
                   exp: &explicit::Exp)
                   -> (Vec<(Typ, Typ)>, Typ) {
    use common::{Const, Op2};
    use explicit::Exp as E;

    match *exp {
        E::Const(Const::Int(_)) => (Vec::new(), Typ::TInt),
        E::Const(Const::Bool(_)) => (Vec::new(), Typ::TBool),
        E::Op2(op, ref e1, ref e2) => {
            let opty = match op {
                Op2::LT | Op2::GT | Op2::Eq => Typ::TBool,
                Op2::Add | Op2::Sub | Op2::Mul => Typ::TInt,
            };
            let (c1, t1) = gen_constraints(m, env, e1);
            let (c2, t2) = gen_constraints(m, env, e2);
            (Vec::new(), Typ::TBool)
        }
        _ => (Vec::new(), Typ::TMetavar((1, String::from("a")))),
    }
}

fn main() {

    let path_s = parse_args();
    let path = Path::new(&path_s);

    // let fd = open(&path);

    // let state = make_state(fd);

    let exp = match implicit_open(&path) {
        Ok(v) => v,
        Err(e) => die!("implicit_open: {}", error::Error::description(&e)),
    };

    let typed_w_metavars = add_metavars(&exp);
    let mut cg_env = MVEnv::new("β");
    let mut id_env = HashMap::new();
    let constraints = gen_constraints(&mut cg_env, &mut id_env, &typed_w_metavars);

    // α β

    // let m = make_machine(&asm);

    // let s = p.main().sim();

    // match s.run_to_end() {
    // 	Ok(_) =>
    //     Err()
    // }

    println!("result:\n\n{:?}", exp);
    println!("typed :\n\n{:?}", typed_w_metavars);
}

macro_rules! test_parse(
    ($s:expr) => { {
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        if let Err(e) = implicit_parse::parse_Program(&s, tokenizer) {
            die!("parse_Program({}): {:?}", $s, e)
        }
    } }
);

macro_rules! test_parse_fails(
    ($s:expr) => { {
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        if let Ok(_) = implicit_parse::parse_Program(&s, tokenizer) {
            die!("parse_Program({}) should have failed", $s)
        }
    } }
);

#[test]
fn implicit_parse() {
    test_parse!("-22");
    test_parse!("(22)");
    test_parse!("((((-22))))");
    test_parse!("((((-22))))");

    test_parse!("1 :: 2 :: empty");
    test_parse!("true :: false :: empty");
    test_parse!("true :: true :: empty");
    test_parse!("(2 + 3 - 2) + 3");
    test_parse!("fun x -> x + 1");
    test_parse!("let inc = fun x -> x + 1 in inc 3");
    test_parse!("let factorial = fix fac -> fun n -> if n = 0 then 1 else n * (fac (n - 1)) in factorial 5");
    test_parse!("let b = true in if b then true else false");
    test_parse!("let double = fun x -> x * 2 in double 3");
    test_parse!("let h = (fun l -> head l) in let l = 1 :: 2 :: empty in (h l) :: l");

    test_parse_fails!("((22)");
    test_parse_fails!("let x = 1"); // only let-in supported
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![feature(if_let)]

#[phase(plugin)]
extern crate rustecs_macros;

extern crate rustecs;
extern crate serialize;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;
use std::default::Default;
use std::rand;
use std::rand::Rng;
use std::num::abs;

use opengl_graphics::{
    Gl,
};
use sdl2_game_window::WindowSDL2;
use piston::{
    EventIterator,
    EventSettings,
    WindowSettings,
};
use piston::graphics::{
    AddBorder,
    AddRectangle,
    AddEllipse,
    AddColor,
    Context,
    Draw,
};
use piston::event::{
    PressEvent,
    ReleaseEvent,
    Event,
    Render,
    Update,
    Input,
};
use piston::input::{
    keyboard,
    Keyboard,
    Button,
};
use rustecs::{
    Entities,
    Components,
};

static WINDOW_W: f64 = 800.0;
static WINDOW_H: f64 = 600.0;

fn draw_system(event: &Event,
              gl: &mut Gl,
              positions: &mut Components<Position>,
              shapes: &mut Components<Shape>,
              colors: &mut Components<Color>) {
    if let &Render(args) = event {
        let w = args.width as f64;
        let h = args.height as f64;
        gl.viewport(0, 0, w as i32, h as i32);
        let c = Context::abs(w, h);
        // Clear background.
        c.rgb(0.2, 0.2, 0.2).draw(gl);
        c.rgb(0.7, 0.7, 0.7).rect(0.0, 0.0, WINDOW_W, WINDOW_H).border_radius(1.0).draw(gl);

        for (eid, pos) in positions.iter_mut() {
          let mut shape = Point;
          let mut border = None;
          if shapes.contains_key(eid) {
            shape = shapes.get_mut(eid).varient;
            border = shapes.get_mut(eid).border;
          }
          let (r, g, b) = if colors.contains_key(eid) {
              (colors.get_mut(eid).r, colors.get_mut(eid).g, colors.get_mut(eid).b)
          } else {
              (1.0, 1.0, 1.0)
          };
          let drawing = c.rgb(r, g, b);
          match (shape, border) {
              (Point, None)    => drawing.rect(1.0, 1.0, w, h).draw(gl),
              (Point, Some(b)) => drawing.rect(1.0, 1.0, w, h).border_radius(b).draw(gl),

              (Circle(rad), None)    => drawing.ellipse(pos.x, pos.y, rad, rad).draw(gl),
              (Circle(rad), Some(b)) => drawing.ellipse(pos.x, pos.y, rad, rad).border_radius(b).draw(gl),

              (Square(w,h), None)    => drawing.rect(pos.x, pos.y, w, h).draw(gl),
              (Square(w,h), Some(b)) => drawing.rect(pos.x, pos.y, w, h).border_radius(b).draw(gl),
          };
        }
    }
}

fn shimmer_system(shimmers: &mut Components<Shimmer>,
                 colors: &mut Components<Color>) {
    for (eid, _) in shimmers.iter_mut() {
        if !colors.contains_key(eid) {
            continue;
        }
        let color = colors.get_mut(eid);
        let ref mut rng = rand::task_rng();
        color.r = rng.gen_range(0.5, 1.0);
        color.g = rng.gen_range(0.5, 1.0);
        color.b = rng.gen_range(0.5, 1.0);
    }
}

fn move_system(event: &Event,
               to_delete: &mut Vec<u32>,
              positions: &mut Components<Position>,
              shapes: &mut Components<Shape>,
              clamps: &mut Components<WindowClamp>,
              velocities: &mut Components<Velocity>) {
    if let &Update(args) = event {
        let dt = args.dt;
        for (eid, position) in positions.iter_mut() {
            if !velocities.contains_key(eid) {
                continue;
            }

            // If we have both a position and a velocity, integrate.
            let velocity = velocities.get_mut(eid);
            position.x += velocity.x * dt;
            position.y += velocity.y * dt;

            if !clamps.contains_key(eid) {
              continue;
            }
            let (w, h) = match shapes.find(eid) {
                Some(&s) =>
                  match s.varient {
                    Circle(r) => (r, r),
                    Square(w,h) => (w, h),
                    Point => (0.0, 0.0)
                  },
                None => (0.0, 0.0)
            };

            let clamp = clamps.get_mut(eid);
            let velocity_mult = match clamp.varient {
              Bounce => -1.0,
              Stop => 0.0,
              _ => 1.0
            };
            match clamp.varient {
              Bounce | Stop => {
                if position.x + w > WINDOW_W {
                  position.x = WINDOW_W - w;
                  velocity.x *= velocity_mult;
                } else if position.x < 0.0 {
                  position.x = 0.0;
                  velocity.x *= velocity_mult;
                }
                if position.y + h > WINDOW_H {
                  position.y = WINDOW_H - h;
                  velocity.y *= velocity_mult;
                } else if position.y < 0.0 {
                  position.y = 0.0;
                  velocity.y *= velocity_mult;
                }
              },
              Remove => {
                if position.x > WINDOW_W
                || position.x + w < 0.0 {
                  to_delete.push(*eid);
                }
                if position.y > WINDOW_H
                || position.y + h < 0.0 {
                  to_delete.push(*eid);
                }
              }
            }
        }
    }
}

fn control_system(event: &Event,
              controllers: &mut Components<PlayerController>,
              velocities: &mut Components<Velocity>) {

    const PADDLE_V: f64 = 800.0;

    for (eid, controller) in controllers.iter_mut() {
        event.press(|button| {
            if button == Keyboard(controller.up) {
                velocities.get_mut(eid).y = -PADDLE_V;
            } else if button == Keyboard(controller.down) {
                velocities.get_mut(eid).y = PADDLE_V;
            }
        });
        event.release(|button| {
            if button == Keyboard(controller.up)
            || button == Keyboard(controller.down) {
                velocities.get_mut(eid).y = 0.0;
            }
        });
    }
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub enum ClampVarient {
    Bounce,
    Stop,
    Remove // Acts when item leaves window.
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct WindowClamp {
    varient: ClampVarient
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct PlayerController {
    up: keyboard::Key,
    down: keyboard::Key
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Position {
    x: f64,
    y: f64
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Shimmer;

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Color {
    r: f32,
    g: f32,
    b: f32
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub enum ShapeVarient {
    Point,
    Circle(f64), // radius
    Square(f64, f64), // width, height
}

impl Default for ShapeVarient {
    fn default() -> ShapeVarient { Point }
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Shape {
    varient: ShapeVarient,
    border: Option<f64>
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Velocity {
    x: f64,
    y: f64
}

world! {
    World,
    components Position, Shape, Velocity, Color, Shimmer, PlayerController,
        WindowClamp;
}

fn make_ball(world: &mut World) {
    const BALL_R: f64 = 20.0;
    let shape = Circle(BALL_R);
    let x = (WINDOW_W - BALL_R) / 2.0;
    let y = (WINDOW_H - BALL_R) / 2.0;

    fn random_vel() -> f64 {
        let ref mut rng = rand::task_rng();
        rng.gen_range(80.0, 100.0) * if rng.gen() { 1.0 } else { -1.0 }
    }

    let e = Entity::new()
        .with_shimmer(Shimmer)
        .with_position(
            Position{
                x: x,
                y: y
            })
        .with_velocity(
            Velocity {
                x: random_vel(),
                y: random_vel()
            })
        .with_shape(
            Shape {
                varient: shape,
                border: None
            })
        .with_color(
            Color{
                r: 1.0,
                g: 0.5,
                b: 0.2
            })
        .with_window_clamp(
            WindowClamp {
               varient: Bounce
            });
    world.add(e);
}

fn make_player(world: &mut World, p1: bool) -> u32 {
    const FROM_WALL: f64 = 20.0;
    const PADDLE_W: f64 = 20.0;
    const PADDLE_H: f64 = 150.0;
    let x = if p1 {
        FROM_WALL
    } else {
        WINDOW_W - FROM_WALL - PADDLE_W
    };
    let y = (WINDOW_H - PADDLE_H) / 2.0;
    let e = Entity::new()
        .with_player_controller(
            PlayerController {
                up: if p1 { keyboard::W } else { keyboard::I },
                down: if p1 { keyboard::S } else { keyboard::K }
            })
        .with_velocity(Velocity { x: 0.0, y: 0.0 } )
        .with_position(
            Position{
                x: x,
                y: y
            })
        .with_shape(
            Shape {
                varient: Square(PADDLE_W, PADDLE_H),
                border: None
            })
        .with_color(
            Color{
                r: 0.5,
                g: 0.2,
                b: 0.8
            })
        .with_window_clamp(
            WindowClamp {
               varient: Stop
            });
    world.add(e)
}

fn main() {
    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "Pong".to_string(),
            size: [WINDOW_W as u32, WINDOW_H as u32],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let mut gl = Gl::new(opengl);
    let mut world = World::new();

    make_player(&mut world, true);
    make_player(&mut world, false);
    make_ball(&mut world);

    let event_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let mut to_delete: Vec<u32> = vec!();
    for e in EventIterator::new(&mut window, &event_settings) {
        control_system(&e, &mut world.player_controllers, &mut world.velocities);
        move_system(&e,
                    &mut to_delete,
                    &mut world.positions,
                    &mut world.shapes,
                    &mut world.window_clamps,
                    &mut world.velocities);
        shimmer_system(&mut world.shimmers, &mut world.colors);
        draw_system(&e, &mut gl, &mut world.positions, &mut world.shapes, &mut world.colors);
        for v in to_delete.iter() {
          world.remove(*v);
        }
        to_delete.clear();
    }
}
<commit_msg>Better starting ball randomization.<commit_after>#![feature(phase)]
#![feature(if_let)]

#[phase(plugin)]
extern crate rustecs_macros;

extern crate rustecs;
extern crate serialize;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;
use std::default::Default;
use std::rand;
use std::rand::Rng;
use std::num::abs;

use opengl_graphics::{
    Gl,
};
use sdl2_game_window::WindowSDL2;
use piston::{
    EventIterator,
    EventSettings,
    WindowSettings,
};
use piston::graphics::{
    AddBorder,
    AddRectangle,
    AddEllipse,
    AddColor,
    Context,
    Draw,
};
use piston::event::{
    PressEvent,
    ReleaseEvent,
    Event,
    Render,
    Update,
    Input,
};
use piston::input::{
    keyboard,
    Keyboard,
    Button,
};
use rustecs::{
    Entities,
    Components,
};

static WINDOW_W: f64 = 800.0;
static WINDOW_H: f64 = 600.0;

fn draw_system(event: &Event,
              gl: &mut Gl,
              positions: &mut Components<Position>,
              shapes: &mut Components<Shape>,
              colors: &mut Components<Color>) {
    if let &Render(args) = event {
        let w = args.width as f64;
        let h = args.height as f64;
        gl.viewport(0, 0, w as i32, h as i32);
        let c = Context::abs(w, h);
        // Clear background.
        c.rgb(0.2, 0.2, 0.2).draw(gl);
        c.rgb(0.7, 0.7, 0.7).rect(0.0, 0.0, WINDOW_W, WINDOW_H).border_radius(1.0).draw(gl);

        for (eid, pos) in positions.iter_mut() {
          let mut shape = Point;
          let mut border = None;
          if shapes.contains_key(eid) {
            shape = shapes.get_mut(eid).varient;
            border = shapes.get_mut(eid).border;
          }
          let (r, g, b) = if colors.contains_key(eid) {
              (colors.get_mut(eid).r, colors.get_mut(eid).g, colors.get_mut(eid).b)
          } else {
              (1.0, 1.0, 1.0)
          };
          let drawing = c.rgb(r, g, b);
          match (shape, border) {
              (Point, None)    => drawing.rect(1.0, 1.0, w, h).draw(gl),
              (Point, Some(b)) => drawing.rect(1.0, 1.0, w, h).border_radius(b).draw(gl),

              (Circle(rad), None)    => drawing.ellipse(pos.x, pos.y, rad, rad).draw(gl),
              (Circle(rad), Some(b)) => drawing.ellipse(pos.x, pos.y, rad, rad).border_radius(b).draw(gl),

              (Square(w,h), None)    => drawing.rect(pos.x, pos.y, w, h).draw(gl),
              (Square(w,h), Some(b)) => drawing.rect(pos.x, pos.y, w, h).border_radius(b).draw(gl),
          };
        }
    }
}

fn shimmer_system(shimmers: &mut Components<Shimmer>,
                 colors: &mut Components<Color>) {
    for (eid, _) in shimmers.iter_mut() {
        if !colors.contains_key(eid) {
            continue;
        }
        let color = colors.get_mut(eid);
        let ref mut rng = rand::task_rng();
        color.r = rng.gen_range(0.5, 1.0);
        color.g = rng.gen_range(0.5, 1.0);
        color.b = rng.gen_range(0.5, 1.0);
    }
}

fn move_system(event: &Event,
               to_delete: &mut Vec<u32>,
              positions: &mut Components<Position>,
              shapes: &mut Components<Shape>,
              clamps: &mut Components<WindowClamp>,
              velocities: &mut Components<Velocity>) {
    if let &Update(args) = event {
        let dt = args.dt;
        for (eid, position) in positions.iter_mut() {
            if !velocities.contains_key(eid) {
                continue;
            }

            // If we have both a position and a velocity, integrate.
            let velocity = velocities.get_mut(eid);
            position.x += velocity.x * dt;
            position.y += velocity.y * dt;

            if !clamps.contains_key(eid) {
              continue;
            }
            let (w, h) = match shapes.find(eid) {
                Some(&s) =>
                  match s.varient {
                    Circle(r) => (r, r),
                    Square(w,h) => (w, h),
                    Point => (0.0, 0.0)
                  },
                None => (0.0, 0.0)
            };

            let clamp = clamps.get_mut(eid);
            let velocity_mult = match clamp.varient {
              Bounce => -1.0,
              Stop => 0.0,
              _ => 1.0
            };
            match clamp.varient {
              Bounce | Stop => {
                if position.x + w > WINDOW_W {
                  position.x = WINDOW_W - w;
                  velocity.x *= velocity_mult;
                } else if position.x < 0.0 {
                  position.x = 0.0;
                  velocity.x *= velocity_mult;
                }
                if position.y + h > WINDOW_H {
                  position.y = WINDOW_H - h;
                  velocity.y *= velocity_mult;
                } else if position.y < 0.0 {
                  position.y = 0.0;
                  velocity.y *= velocity_mult;
                }
              },
              Remove => {
                if position.x > WINDOW_W
                || position.x + w < 0.0 {
                  to_delete.push(*eid);
                }
                if position.y > WINDOW_H
                || position.y + h < 0.0 {
                  to_delete.push(*eid);
                }
              }
            }
        }
    }
}

fn control_system(event: &Event,
              controllers: &mut Components<PlayerController>,
              velocities: &mut Components<Velocity>) {

    const PADDLE_V: f64 = 800.0;

    for (eid, controller) in controllers.iter_mut() {
        event.press(|button| {
            if button == Keyboard(controller.up) {
                velocities.get_mut(eid).y = -PADDLE_V;
            } else if button == Keyboard(controller.down) {
                velocities.get_mut(eid).y = PADDLE_V;
            }
        });
        event.release(|button| {
            if button == Keyboard(controller.up)
            || button == Keyboard(controller.down) {
                velocities.get_mut(eid).y = 0.0;
            }
        });
    }
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub enum ClampVarient {
    Bounce,
    Stop,
    Remove // Acts when item leaves window.
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct WindowClamp {
    varient: ClampVarient
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct PlayerController {
    up: keyboard::Key,
    down: keyboard::Key
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Position {
    x: f64,
    y: f64
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Shimmer;

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Color {
    r: f32,
    g: f32,
    b: f32
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub enum ShapeVarient {
    Point,
    Circle(f64), // radius
    Square(f64, f64), // width, height
}

impl Default for ShapeVarient {
    fn default() -> ShapeVarient { Point }
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Shape {
    varient: ShapeVarient,
    border: Option<f64>
}

#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
pub struct Velocity {
    x: f64,
    y: f64
}

world! {
    World,
    components Position, Shape, Velocity, Color, Shimmer, PlayerController,
        WindowClamp;
}

fn make_ball(world: &mut World) {
    const BALL_R: f64 = 20.0;
    let shape = Circle(BALL_R);
    let x = (WINDOW_W - BALL_R) / 2.0;
    let y = (WINDOW_H - BALL_R) / 2.0;

    let ref mut rng = rand::task_rng();
    let vx = rng.gen_range(100.0, 200.0) * if rng.gen() { 1.0 } else { -1.0 };
    let vy = rng.gen_range(-200.0, 200.0);

    let e = Entity::new()
        .with_shimmer(Shimmer)
        .with_position(
            Position{
                x: x,
                y: y
            })
        .with_velocity(
            Velocity {
                x: vx,
                y: vy
            })
        .with_shape(
            Shape {
                varient: shape,
                border: None
            })
        .with_color(
            Color{
                r: 1.0,
                g: 0.5,
                b: 0.2
            })
        .with_window_clamp(
            WindowClamp {
               varient: Bounce
            });
    world.add(e);
}

fn make_player(world: &mut World, p1: bool) -> u32 {
    const FROM_WALL: f64 = 20.0;
    const PADDLE_W: f64 = 20.0;
    const PADDLE_H: f64 = 150.0;
    let x = if p1 {
        FROM_WALL
    } else {
        WINDOW_W - FROM_WALL - PADDLE_W
    };
    let y = (WINDOW_H - PADDLE_H) / 2.0;
    let e = Entity::new()
        .with_player_controller(
            PlayerController {
                up: if p1 { keyboard::W } else { keyboard::I },
                down: if p1 { keyboard::S } else { keyboard::K }
            })
        .with_velocity(Velocity { x: 0.0, y: 0.0 } )
        .with_position(
            Position{
                x: x,
                y: y
            })
        .with_shape(
            Shape {
                varient: Square(PADDLE_W, PADDLE_H),
                border: None
            })
        .with_color(
            Color{
                r: 0.5,
                g: 0.2,
                b: 0.8
            })
        .with_window_clamp(
            WindowClamp {
               varient: Stop
            });
    world.add(e)
}

fn main() {
    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "Pong".to_string(),
            size: [WINDOW_W as u32, WINDOW_H as u32],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let mut gl = Gl::new(opengl);
    let mut world = World::new();

    make_player(&mut world, true);
    make_player(&mut world, false);
    make_ball(&mut world);

    let event_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let mut to_delete: Vec<u32> = vec!();
    for e in EventIterator::new(&mut window, &event_settings) {
        control_system(&e, &mut world.player_controllers, &mut world.velocities);
        move_system(&e,
                    &mut to_delete,
                    &mut world.positions,
                    &mut world.shapes,
                    &mut world.window_clamps,
                    &mut world.velocities);
        shimmer_system(&mut world.shimmers, &mut world.colors);
        draw_system(&e, &mut gl, &mut world.positions, &mut world.shapes, &mut world.colors);
        for v in to_delete.iter() {
          world.remove(*v);
        }
        to_delete.clear();
    }
}
<|endoftext|>