<commit_before>#[macro_use] extern crate clap;
#[macro_use] extern crate prettytable;
extern crate mio_uds;
extern crate rand;
extern crate sozu_command_lib as sozu_command;

mod command;

use mio_uds::UnixStream;
use clap::{App,Arg,SubCommand};

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::data::{ConfigMessage,ConfigMessageAnswer};

use command::{add_application,remove_application,dump_state,load_state,save_state,soft_stop,hard_stop,upgrade,status,metrics,
  remove_backend, add_backend, remove_frontend, add_frontend, add_certificate, remove_certificate, query_application,
  logging_filter};

use std::str::FromStr;

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(option_env!("SOZU_CONFIG").is_none()))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("upgrades the proxy"))
                        .subcommand(SubCommand::with_name("status")
                                    .about("gets information on the running workers"))
                        .subcommand(SubCommand::with_name("metrics")
                                    .about("gets statistics on the master and its workers"))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .subcommand(SubCommand::with_name("application")
                                                .about("application management")
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("application identifier")
                                                      .takes_value(true)
                                                      .required(true)))
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("application identifier")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("sticky_session")
                                                      .long("sticky session")
                                                      .value_name("the frontend should do sticky session")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("backend")
                                                .about("backend management")
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("instance-id")
                                                      .long("instance-id")
                                                      .value_name("id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true)))
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("instance-id")
                                                      .long("instance-id")
                                                      .value_name("id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true))))
                        .subcommand(SubCommand::with_name("frontend")
                                                .about("frontend management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false))
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to a certificate file")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false))
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to a certificate file")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("certificate")
                                                .about("certificate management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("certificate chain")
                                                      .short("chain")
                                                      .long("certificate-chain")
                                                      .value_name("path to the certificate chain")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("key")
                                                      .long("key")
                                                      .value_name("path to the key")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))))
                        .subcommand(SubCommand::with_name("query")
                                                .about("configuration state verification")
                                                .subcommand(SubCommand::with_name("applications")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("application identifier")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("logging")
                                                .about("change logging level")
                                                .arg(Arg::with_name("level")
                                                  .short("l")
                                                  .long("level")
                                                  .value_name("logging level")
                                                  .takes_value(true)
                                                  .required(true)))
                        .get_matches();

  let config_file = match matches.value_of("config"){
                      Some(config_file) => config_file,
                      None => option_env!("SOZU_CONFIG").expect("could not find `SOZU_CONFIG` env var at build"),
                    };

  let config = Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(&config.command_socket_path()).expect("could not connect to the command unix socket");
  let mut channel: Channel<ConfigMessage,ConfigMessageAnswer> = Channel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
      if hard_shutdown {
        hard_stop(&mut channel);
      } else {
        soft_stop(&mut channel);
      }
    },
    ("upgrade", Some(_)) => {
      upgrade(&mut channel);
    },
    ("status", Some(_)) => {
      status(channel);
    },
    ("metrics", Some(_)) => {
      metrics(&mut channel);
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          save_state(&mut channel, file);
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          load_state(&mut channel, file);
        },
        ("dump", _) => {
          dump_state(&mut channel);
        },
        _                   => println!("unknown state management command")
      }
    },
    ("application", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(app_sub)) => {
          let id = app_sub.value_of("id").expect("missing id");
          remove_application(&mut channel, id);
        }
        ("add", Some(app_sub)) => {
          let id = app_sub.value_of("id").expect("missing id");
          let sticky_session  = app_sub.value_of("sticky_session").and_then(|b| bool::from_str(b).ok()).unwrap_or(false);
          add_application(&mut channel, id, sticky_session);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("backend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let instance_id = backend_sub.value_of("instance-id").expect("missing instance id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          remove_backend(&mut channel, id, instance_id, ip, port);
        }
        ("add", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let instance_id = backend_sub.value_of("instance-id").expect("missing instance id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          add_backend(&mut channel, id, instance_id, ip, port);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("frontend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(frontend_sub)) => {
          let id              = frontend_sub.value_of("id").expect("missing id");
          let hostname        = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin      = frontend_sub.value_of("path_begin").unwrap_or("");
          let certificate     = frontend_sub.value_of("certificate");
          remove_frontend(&mut channel, id, hostname, path_begin, certificate);
        },
        ("add", Some(frontend_sub)) => {
          let id              = frontend_sub.value_of("id").expect("missing id");
          let hostname        = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin      = frontend_sub.value_of("path_begin").unwrap_or("");
          let certificate     = frontend_sub.value_of("certificate");
          add_frontend(&mut channel, id, hostname, path_begin, certificate);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("certificate", Some(sub)) => {
      match sub.subcommand() {
        ("add", Some(cert_sub)) => {
          let certificate = cert_sub.value_of("certificate").expect("missing certificate path");
          let chain       = cert_sub.value_of("certificate-chain").expect("missing certificate chain path");
          let key         = cert_sub.value_of("key").unwrap_or("missing key path");
          add_certificate(&mut channel, certificate, chain, key);
        }
        ("remove", Some(cert_sub)) => {
          let certificate = cert_sub.value_of("certificate").expect("missing certificate path");
          remove_certificate(&mut channel, certificate);
        },
        _ => println!("unknown backend management command")
      }
    },
    ("query", Some(sub)) => {
      match sub.subcommand() {
        ("applications", Some(frontend_sub)) => {
          let id              = frontend_sub.value_of("id");
          query_application(&mut channel, id);
        },
        _ => println!("unknown query command")
      }
    },
    ("logging", Some(sub)) => {
      let level = sub.value_of("level").expect("missing logging level");
      logging_filter(&mut channel, level);
    },
    _                => println!("unknown subcommand")
  }

}
<commit_msg>increase max channel size for ctl<commit_after>#[macro_use] extern crate clap;
#[macro_use] extern crate prettytable;
extern crate mio_uds;
extern crate rand;
extern crate sozu_command_lib as sozu_command;

mod command;

use mio_uds::UnixStream;
use clap::{App,Arg,SubCommand};

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::data::{ConfigMessage,ConfigMessageAnswer};

use command::{add_application,remove_application,dump_state,load_state,save_state,soft_stop,hard_stop,upgrade,status,metrics,
  remove_backend, add_backend, remove_frontend, add_frontend, add_certificate, remove_certificate, query_application,
  logging_filter};

use std::str::FromStr;

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(option_env!("SOZU_CONFIG").is_none()))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("upgrades the proxy"))
                        .subcommand(SubCommand::with_name("status")
                                    .about("gets information on the running workers"))
                        .subcommand(SubCommand::with_name("metrics")
                                    .about("gets statistics on the master and its workers"))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .subcommand(SubCommand::with_name("application")
                                                .about("application management")
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("application identifier")
                                                      .takes_value(true)
                                                      .required(true)))
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("application identifier")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("sticky_session")
                                                      .long("sticky session")
                                                      .value_name("the frontend should do sticky session")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("backend")
                                                .about("backend management")
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("instance-id")
                                                      .long("instance-id")
                                                      .value_name("id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true)))
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("instance-id")
                                                      .long("instance-id")
                                                      .value_name("id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true))))
                        .subcommand(SubCommand::with_name("frontend")
                                                .about("frontend management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false))
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to a certificate file")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false))
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to a certificate file")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("certificate")
                                                .about("certificate management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("certificate chain")
                                                      .short("chain")
                                                      .long("certificate-chain")
                                                      .value_name("path to the certificate chain")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("key")
                                                      .long("key")
                                                      .value_name("path to the key")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))))
                        .subcommand(SubCommand::with_name("query")
                                                .about("configuration state verification")
                                                .subcommand(SubCommand::with_name("applications")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("application identifier")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("logging")
                                                .about("change logging level")
                                                .arg(Arg::with_name("level")
                                                  .short("l")
                                                  .long("level")
                                                  .value_name("logging level")
                                                  .takes_value(true)
                                                  .required(true)))
                        .get_matches();

  let config_file = match matches.value_of("config"){
                      Some(config_file) => config_file,
                      None => option_env!("SOZU_CONFIG").expect("could not find `SOZU_CONFIG` env var at build"),
                    };

  let config = Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(&config.command_socket_path()).expect("could not connect to the command unix socket");
  let mut channel: Channel<ConfigMessage,ConfigMessageAnswer> = Channel::new(stream, 10_000, 2_000_000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
      if hard_shutdown {
        hard_stop(&mut channel);
      } else {
        soft_stop(&mut channel);
      }
    },
    ("upgrade", Some(_)) => {
      upgrade(&mut channel);
    },
    ("status", Some(_)) => {
      status(channel);
    },
    ("metrics", Some(_)) => {
      metrics(&mut channel);
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          save_state(&mut channel, file);
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          load_state(&mut channel, file);
        },
        ("dump", _) => {
          dump_state(&mut channel);
        },
        _                   => println!("unknown state management command")
      }
    },
    ("application", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(app_sub)) => {
          let id = app_sub.value_of("id").expect("missing id");
          remove_application(&mut channel, id);
        }
        ("add", Some(app_sub)) => {
          let id = app_sub.value_of("id").expect("missing id");
          let sticky_session  = app_sub.value_of("sticky_session").and_then(|b| bool::from_str(b).ok()).unwrap_or(false);
          add_application(&mut channel, id, sticky_session);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("backend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let instance_id = backend_sub.value_of("instance-id").expect("missing instance id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          remove_backend(&mut channel, id, instance_id, ip, port);
        }
        ("add", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let instance_id = backend_sub.value_of("instance-id").expect("missing instance id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          add_backend(&mut channel, id, instance_id, ip, port);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("frontend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(frontend_sub)) => {
          let id              = frontend_sub.value_of("id").expect("missing id");
          let hostname        = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin      = frontend_sub.value_of("path_begin").unwrap_or("");
          let certificate     = frontend_sub.value_of("certificate");
          remove_frontend(&mut channel, id, hostname, path_begin, certificate);
        },
        ("add", Some(frontend_sub)) => {
          let id              = frontend_sub.value_of("id").expect("missing id");
          let hostname        = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin      = frontend_sub.value_of("path_begin").unwrap_or("");
          let certificate     = frontend_sub.value_of("certificate");
          add_frontend(&mut channel, id, hostname, path_begin, certificate);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("certificate", Some(sub)) => {
      match sub.subcommand() {
        ("add", Some(cert_sub)) => {
          let certificate = cert_sub.value_of("certificate").expect("missing certificate path");
          let chain       = cert_sub.value_of("certificate-chain").expect("missing certificate chain path");
          let key         = cert_sub.value_of("key").unwrap_or("missing key path");
          add_certificate(&mut channel, certificate, chain, key);
        }
        ("remove", Some(cert_sub)) => {
          let certificate = cert_sub.value_of("certificate").expect("missing certificate path");
          remove_certificate(&mut channel, certificate);
        },
        _ => println!("unknown backend management command")
      }
    },
    ("query", Some(sub)) => {
      match sub.subcommand() {
        ("applications", Some(frontend_sub)) => {
          let id              = frontend_sub.value_of("id");
          query_application(&mut channel, id);
        },
        _ => println!("unknown query command")
      }
    },
    ("logging", Some(sub)) => {
      let level = sub.value_of("level").expect("missing logging level");
      logging_filter(&mut channel, level);
    },
    _                => println!("unknown subcommand")
  }

}
<|endoftext|>


<commit_before>// `cargo test --benches` and `#[feature(test)]` work only in nightly
#![cfg(rustc_nightly)]
#![cfg(feature = "bytes")]
#![feature(test)]
use std::fmt::Write;

use bytes::Bytes;
use perftest_bytes::messages;
use protobuf::Message;

fn make_string_of_len(len: usize) -> String {
    let mut s = String::new();
    for i in 0..len {
        write!(s, "{}", i % 10).expect("unreachable");
    }
    s
}

fn make_repeated(len: usize) -> Vec<u8> {
    let mut m = messages::TestMessage::new();

    for i in 0..100 {
        m.sr.push(make_string_of_len(i % len));
        m.br.push(make_string_of_len((i + len / 2) % len).into_bytes());
    }

    m.write_to_bytes().expect("write")
}

#[bench]
fn parse_repeated_small_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_small_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_regular(b: &mut test::Bencher) {
    let bs = make_repeated(300);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(300));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_regular(b: &mut test::Bencher) {
    let bs = make_repeated(3000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(3000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}
<commit_msg>Restore extern crate test to fix bench compilation<commit_after>// `cargo test --benches` and `#[feature(test)]` work only in nightly
#![cfg(rustc_nightly)]
#![cfg(feature = "bytes")]
#![feature(test)]

extern crate test;

use std::fmt::Write;

use bytes::Bytes;
use perftest_bytes::messages;
use protobuf::Message;

fn make_string_of_len(len: usize) -> String {
    let mut s = String::new();
    for i in 0..len {
        write!(s, "{}", i % 10).expect("unreachable");
    }
    s
}

fn make_repeated(len: usize) -> Vec<u8> {
    let mut m = messages::TestMessage::new();

    for i in 0..100 {
        m.sr.push(make_string_of_len(i % len));
        m.br.push(make_string_of_len((i + len / 2) % len).into_bytes());
    }

    m.write_to_bytes().expect("write")
}

#[bench]
fn parse_repeated_small_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_small_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_regular(b: &mut test::Bencher) {
    let bs = make_repeated(300);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(300));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_regular(b: &mut test::Bencher) {
    let bs = make_repeated(3000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(3000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}
<|endoftext|>


<commit_before>use std::num::Int;

use cpu::exec::fetch_exec;
use mmu::Memory;
use symbols::{SymbolTable, build_symbol_table};

pub mod exec;
pub mod disasm;

const DEBUG: bool = false;

const INTERRUPT_TABLE: &'static [u16] = &[
    0x0040,   // V-Blank
    0x0048,   // LCD STAT
    0x0050,   // Timer
    0x0058,   // Serial
    0x0060,   // Joypad
];

// FIXME(minor): Remove this allow when the remaining interrupts have been implemented
#[allow(dead_code)]
#[repr(u8)]
pub enum Interrupt {
    VBlank = 0b00000001,
    Stat   = 0b00000010,
    Timer  = 0b00000100,
    Serial = 0b00001000,
    Joypad = 0b00010000,
}

#[deriving(PartialEq)]
pub enum State {
    Running,
    Stopped,
    Halted,
}

/// The main processor for GB/C. The processor is similar to the Z80 processor, with a few
/// differences (see: http://www.devrs.com/gb/files/gbspec.txt)
///
/// # Registers
///
/// * a,b,c,d,e,f,h,l : main register set (8-bit)
/// * sp : Stack pointer (16-bit)
/// * pc : Program counter (16-bit)
/// * ime : Interrupt flags register (8-bit)
///
/// In addition, the main register set can be combined into 16-bit registers: af, bc, de, hl
pub struct Cpu {
    pub crashed: bool,

    pub a: u8,
    pub b: u8,
    pub c: u8,
    pub d: u8,
    pub e: u8,
    pub f: u8,
    pub h: u8,
    pub l: u8,

    pub ime: u8,

    pub sp: u16,
    pub pc: u16,

    pub state: State,
    pub clock: u8,

    symbols: SymbolTable,
    stack_depth: i32,

    prev: u16,
    loop_count: u32,
}

impl Cpu {
    pub fn new() -> Cpu {
        Cpu {
            crashed: true,

            a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, h: 0, l: 0,

            ime: 0,

            sp: 0,
            pc: 0,

            state: State::Running,
            clock: 0,

            symbols: build_symbol_table(include_str!("testGame2.sym")),
            stack_depth: 0,

            prev: 0,
            loop_count: 0,
        }
    }

    pub fn start_up(&mut self) {
        // TODO(major): Add support for SGB and CGB
        self.af().set(0x01B0);
        self.bc().set(0x0013);
        self.de().set(0x00D8);
        self.hl().set(0x014D);
        self.sp = 0xFFFE;
        self.pc = 0x0100;

        self.crashed = false;
    }

    /// Steps the CPU returning the number of elapsed cycles
    pub fn step(&mut self, mem: &mut Memory) -> u8 {
        if self.crashed {
            // If the CPU has crashed, then we can't do anything
            return 0xFF;
        }

        let mut elapsed_cycles = 0;
        if self.ime != 0 {
            elapsed_cycles += self.handle_interrupts(mem);
        }

        if self.state != State::Halted && self.state != State::Stopped {
            // println!("{:04X}:\t\t{}", self.pc, disasm::disasm(self.pc, mem));
            elapsed_cycles += fetch_exec(self, mem);
        }
        else {
            elapsed_cycles += 1;
        }

        // TODO: add support for CGB double speed mode
        self.clock += elapsed_cycles * 4;

        elapsed_cycles * 4
    }

    /// Handles interrupts
    /// Returns the amount of elapsed cycles (if any) as a result of processing interrupts.
    fn handle_interrupts(&mut self, mem: &mut Memory) -> u8 {
        let interrupts = mem.if_reg & mem.ie_reg;

        if interrupts == 0 {
            return 0;
        }

        // Disable interrupts
        self.disable_interrupts(mem);

        // Get the highest priority interrupt
        let i = interrupts.trailing_zeros();
        mem.if_reg &= !(1 << i);

        // Call the correct correct interrupt handler
        self.call(mem, INTERRUPT_TABLE[i]);
        self.state = State::Running;

        1
    }

    /// Enables CPU interrupts
    fn enable_interrupts(&mut self, _mem: &mut Memory) {
        self.ime = 1;
    }

    /// Disables CPU interrupts
    fn disable_interrupts(&mut self, _mem: &mut Memory) {
        self.ime = 0;
    }

    /// Jumps to a location
    fn jump(&mut self, mem: &mut Memory, addr: u16) {
        self.pc = addr;

        if DEBUG {
            if self.pc == self.prev {
                self.loop_count += 1;
                return;
            }
            else {
                if self.loop_count != 0 {
                    for _ in range(0, self.stack_depth) { print!("    "); }
                    println!("x {}", self.loop_count);
                    self.loop_count = 0;
                }
                self.prev = self.pc;
            }

            for _ in range(0, self.stack_depth) { print!("    "); }
            let bank_num = if self.pc < 0x4000 { 0 } else { mem.rom_bank as u8 };
            match self.symbols.get(&(bank_num, self.pc)) {
                Some(name) => println!("->{}", name),
                None => println!("->{:02X}:{:04X}", bank_num, self.pc),
            }
        }
    }

    fn call(&mut self, mem: &mut Memory, addr: u16) {
        self.sp -= 2;
        mem.sw(self.sp, self.pc);
        self.pc = addr;

        if DEBUG {
            for _ in range(0, self.stack_depth) { print!("    "); }
            let bank_num = if self.pc < 0x4000 { 0 } else { mem.rom_bank as u8 };
            match self.symbols.get(&(bank_num, self.pc)) {
                Some(name) => println!("CALL: {}", name),
                None => println!("CALL: {:02X}:{:04X}", bank_num, self.pc),
            }
        }
        if self.stack_depth < 0 { self.stack_depth = 0; }
        self.stack_depth += 1;
    }

    fn ret(&mut self, mem: &mut Memory) {
        self.pc = mem.lw(self.sp);
        self.sp += 2;

        self.stack_depth -= 1;
        if DEBUG {
            for _ in range(0, self.stack_depth) { print!("    "); }
            println!("RETURN");
        }
    }

    /// Handle instructions corresponding to invalid opcodes
    fn invalid_inst(&mut self, _opcode: u8) -> u8 {
        self.crashed = true;
        0
    }

    /// Halt the cpu
    fn halt(&mut self) {
        self.state = State::Halted;
    }

    /// Stop the cpu
    fn stop(&mut self) {
        self.state = State::Stopped;
    }

    /// Increments the program counter, returning the old value
    pub fn bump(&mut self) -> u16 {
        self.pc += 1;
        self.pc - 1
    }
}

// The 8-bit registers in the main register set can be joint to form 16-bit registers.
macro_rules! join_regs { (($r1: ident, $r2: ident) as $name: ident) => (
    #[allow(dead_code)]
    impl Cpu {
        pub fn $name(&mut self) -> JointReg {
            JointReg {
                high: &mut self.$r1,
                low: &mut self.$r2,
            }
        }
    }
) }

join_regs!((b, c) as bc)
join_regs!((d, e) as de)
join_regs!((h, l) as hl)
join_regs!((a, f) as af)

struct JointReg<'a> {
    high: &'a mut u8,
    low: &'a mut u8,
}

impl<'a> JointReg<'a> {
    #[inline(always)]
    pub fn set(&mut self, value: u16) {
        *self.high = (value >> 8) as u8;
        *self.low = value as u8;
    }

    #[inline(always)]
    pub fn get(&self) -> u16 {
        (*self.high as u16 << 8) + *self.low as u16
    }
}
<commit_msg>Fix debug info indentation when dealing with manually created stack frames.<commit_after>use std::num::Int;

use cpu::exec::fetch_exec;
use mmu::Memory;
use symbols::{SymbolTable, build_symbol_table};

pub mod exec;
pub mod disasm;

const DEBUG: bool = false;

const INTERRUPT_TABLE: &'static [u16] = &[
    0x0040,   // V-Blank
    0x0048,   // LCD STAT
    0x0050,   // Timer
    0x0058,   // Serial
    0x0060,   // Joypad
];

// FIXME(minor): Remove this allow when the remaining interrupts have been implemented
#[allow(dead_code)]
#[repr(u8)]
pub enum Interrupt {
    VBlank = 0b00000001,
    Stat   = 0b00000010,
    Timer  = 0b00000100,
    Serial = 0b00001000,
    Joypad = 0b00010000,
}

#[deriving(PartialEq)]
pub enum State {
    Running,
    Stopped,
    Halted,
}

/// The main processor for GB/C. The processor is similar to the Z80 processor, with a few
/// differences (see: http://www.devrs.com/gb/files/gbspec.txt)
///
/// # Registers
///
/// * a,b,c,d,e,f,h,l : main register set (8-bit)
/// * sp : Stack pointer (16-bit)
/// * pc : Program counter (16-bit)
/// * ime : Interrupt flags register (8-bit)
///
/// In addition, the main register set can be combined into 16-bit registers: af, bc, de, hl
pub struct Cpu {
    pub crashed: bool,

    pub a: u8,
    pub b: u8,
    pub c: u8,
    pub d: u8,
    pub e: u8,
    pub f: u8,
    pub h: u8,
    pub l: u8,

    pub ime: u8,

    pub sp: u16,
    pub pc: u16,

    pub state: State,
    pub clock: u8,

    symbols: SymbolTable,
    stack_depth: i32,
    stack_addr: Vec<u16>,

    prev: u16,
    loop_count: u32,
}

impl Cpu {
    pub fn new() -> Cpu {
        Cpu {
            crashed: true,

            a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, h: 0, l: 0,

            ime: 0,

            sp: 0,
            pc: 0,

            state: State::Running,
            clock: 0,

            symbols: build_symbol_table(include_str!("testGame5.sym")),
            stack_depth: 0,
            stack_addr: vec![],

            prev: 0,
            loop_count: 0,
        }
    }

    pub fn start_up(&mut self) {
        // TODO(major): Add support for SGB and CGB
        self.af().set(0x01B0);
        self.bc().set(0x0013);
        self.de().set(0x00D8);
        self.hl().set(0x014D);
        self.sp = 0xFFFE;
        self.pc = 0x0100;

        self.crashed = false;
    }

    /// Steps the CPU returning the number of elapsed cycles
    pub fn step(&mut self, mem: &mut Memory) -> u8 {
        if self.crashed {
            // If the CPU has crashed, then we can't do anything
            return 0xFF;
        }

        let mut elapsed_cycles = 0;
        if self.ime != 0 {
            elapsed_cycles += self.handle_interrupts(mem);
        }

        if self.state != State::Halted && self.state != State::Stopped {
            // println!("{:04X}:\t\t{}", self.pc, disasm::disasm(self.pc, mem));
            elapsed_cycles += fetch_exec(self, mem);
        }
        else {
            elapsed_cycles += 1;
        }

        // TODO: add support for CGB double speed mode
        self.clock += elapsed_cycles * 4;

        elapsed_cycles * 4
    }

    /// Handles interrupts
    /// Returns the amount of elapsed cycles (if any) as a result of processing interrupts.
    fn handle_interrupts(&mut self, mem: &mut Memory) -> u8 {
        let interrupts = mem.if_reg & mem.ie_reg;

        if interrupts == 0 {
            return 0;
        }

        // Disable interrupts
        self.disable_interrupts(mem);

        // Get the highest priority interrupt
        let i = interrupts.trailing_zeros();
        mem.if_reg &= !(1 << i);

        // Call the correct correct interrupt handler
        self.call(mem, INTERRUPT_TABLE[i]);
        self.state = State::Running;

        1
    }

    /// Enables CPU interrupts
    fn enable_interrupts(&mut self, _mem: &mut Memory) {
        self.ime = 1;
    }

    /// Disables CPU interrupts
    fn disable_interrupts(&mut self, _mem: &mut Memory) {
        self.ime = 0;
    }

    /// Jumps to a location
    fn jump(&mut self, mem: &mut Memory, addr: u16) {
        self.pc = addr;

        if DEBUG {
            if self.pc == self.prev {
                self.loop_count += 1;
                return;
            }
            else {
                if self.loop_count != 0 {
                    for _ in range(0, self.stack_depth) { print!("    "); }
                    println!("x {}", self.loop_count);
                    self.loop_count = 0;
                }
                self.prev = self.pc;
            }

            for _ in range(0, self.stack_depth) { print!("    "); }
            let bank_num = if self.pc < 0x4000 { 0 } else { mem.rom_bank as u8 };
            match self.symbols.get(&(bank_num, self.pc)) {
                Some(name) => println!("->{}", name),
                None => println!("->{:02X}:{:04X}", bank_num, self.pc),
            }
        }
    }

    fn call(&mut self, mem: &mut Memory, addr: u16) {
        self.sp -= 2;
        mem.sw(self.sp, self.pc);
        self.pc = addr;

        if DEBUG {
            self.stack_addr.push(mem.lw(self.sp));

            for _ in range(0, self.stack_depth) { print!("    "); }
            let bank_num = if self.pc < 0x4000 { 0 } else { mem.rom_bank as u8 };
            match self.symbols.get(&(bank_num, self.pc)) {
                Some(name) => println!("CALL: {}", name),
                None => println!("CALL: {:02X}:{:04X}", bank_num, self.pc),
            }
        }
        if self.stack_depth < 0 { self.stack_depth = 0; }
        self.stack_depth += 1;
    }

    fn ret(&mut self, mem: &mut Memory) {
        self.pc = mem.lw(self.sp);
        self.sp += 2;

        if DEBUG {
            if self.stack_addr.last() == Some(&self.pc) {
                self.stack_addr.pop();
                self.stack_depth -= 1;

                for _ in range(0, self.stack_depth) { print!("    "); }
                println!("RETURN");
            }
            else {
                for _ in range(0, self.stack_depth) { print!("    "); }
                println!("..RETURN");
            }
        }
    }

    /// Handle instructions corresponding to invalid opcodes
    fn invalid_inst(&mut self, _opcode: u8) -> u8 {
        self.crashed = true;
        0
    }

    /// Halt the cpu
    fn halt(&mut self) {
        self.state = State::Halted;
    }

    /// Stop the cpu
    fn stop(&mut self) {
        self.state = State::Stopped;
    }

    /// Increments the program counter, returning the old value
    pub fn bump(&mut self) -> u16 {
        self.pc += 1;
        self.pc - 1
    }
}

// The 8-bit registers in the main register set can be joint to form 16-bit registers.
macro_rules! join_regs { (($r1: ident, $r2: ident) as $name: ident) => (
    #[allow(dead_code)]
    impl Cpu {
        pub fn $name(&mut self) -> JointReg {
            JointReg {
                high: &mut self.$r1,
                low: &mut self.$r2,
            }
        }
    }
) }

join_regs!((b, c) as bc)
join_regs!((d, e) as de)
join_regs!((h, l) as hl)
join_regs!((a, f) as af)

struct JointReg<'a> {
    high: &'a mut u8,
    low: &'a mut u8,
}

impl<'a> JointReg<'a> {
    #[inline(always)]
    pub fn set(&mut self, value: u16) {
        *self.high = (value >> 8) as u8;
        *self.low = value as u8;
    }

    #[inline(always)]
    pub fn get(&self) -> u16 {
        (*self.high as u16 << 8) + *self.low as u16
    }
}
<|endoftext|>


<commit_before>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new<'r>(name: &str) {
    let home_unwrap = homedir().unwrap();
    let path = format!("{}/.muxed/{}", home_unwrap.display(), name);
    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}
#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name);
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<commit_msg>Convenience method for seeing if the mixed dir exists.<commit_after>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new<'r>(name: &str) {
    let home_unwrap = homedir().unwrap();
    let path = format!("{}/.muxed/{}", home_unwrap.display(), name);
    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    path.exists()
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let home_unwrap = homedir().unwrap();
  let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name);
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fmt;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result as IoResult;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R>
where
    R: Read,
{
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source,
            remaining_chunks_size: None,
        }
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size_bytes = Vec::new();
        let mut has_ext = false;

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => b?,
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            if byte == b';' {
                has_ext = true;
                break;
            }

            chunk_size_bytes.push(byte);
        }

        // Ignore extensions for now
        if has_ext {
            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => b?,
                    None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                };
                if byte == b'\r' {
                    break;
                }
            }
        }

        self.read_line_feed()?;

        let chunk_size = String::from_utf8(chunk_size_bytes)
            .ok()
            .and_then(|c| usize::from_str_radix(c.trim(), 16).ok())
            .ok_or(IoError::new(ErrorKind::InvalidInput, DecoderError))?;

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R>
where
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = self.read_chunk_size()?;

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    self.read_carriage_return()?;
                    self.read_line_feed()?;
                    return Ok(0);
                }

                chunk_size
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = self.source.read(buf)?;
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[..remaining_chunks_size];
        let read = self.source.read(buf)?;

        self.remaining_chunks_size = if read == remaining_chunks_size {
            self.read_carriage_return()?;
            self.read_line_feed()?;
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        Ok(read)
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    /// This unit test is taken from from Hyper
    /// https://github.com/hyperium/hyper
    /// Copyright (c) 2014 Sean McArthur
    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, expected: usize) {
            let mut decoded = Decoder::new(s.as_bytes());
            let actual = decoded.read_chunk_size().unwrap();
            assert_eq!(expected, actual);
        }

        fn read_err(s: &str) {
            let mut decoded = Decoder::new(s.as_bytes());
            let err_kind = decoded.read_chunk_size().unwrap_err().kind();
            assert_eq!(err_kind, io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new(
            "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new(
            "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new(
            "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }
}
<commit_msg>Add Decoder::unwrap method to enable unsafe code removal in ureq.<commit_after>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fmt;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result as IoResult;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R>
{
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source,
            remaining_chunks_size: None,
        }
    }

    /// Unwraps the inner read source.
    pub fn unwrap(self) -> R {
        self.source
    }
}

impl<R> Decoder<R>
where
    R: Read,
{
    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size_bytes = Vec::new();
        let mut has_ext = false;

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => b?,
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            if byte == b';' {
                has_ext = true;
                break;
            }

            chunk_size_bytes.push(byte);
        }

        // Ignore extensions for now
        if has_ext {
            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => b?,
                    None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                };
                if byte == b'\r' {
                    break;
                }
            }
        }

        self.read_line_feed()?;

        let chunk_size = String::from_utf8(chunk_size_bytes)
            .ok()
            .and_then(|c| usize::from_str_radix(c.trim(), 16).ok())
            .ok_or(IoError::new(ErrorKind::InvalidInput, DecoderError))?;

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R>
where
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = self.read_chunk_size()?;

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    self.read_carriage_return()?;
                    self.read_line_feed()?;
                    return Ok(0);
                }

                chunk_size
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = self.source.read(buf)?;
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[..remaining_chunks_size];
        let read = self.source.read(buf)?;

        self.remaining_chunks_size = if read == remaining_chunks_size {
            self.read_carriage_return()?;
            self.read_line_feed()?;
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        Ok(read)
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    /// This unit test is taken from from Hyper
    /// https://github.com/hyperium/hyper
    /// Copyright (c) 2014 Sean McArthur
    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, expected: usize) {
            let mut decoded = Decoder::new(s.as_bytes());
            let actual = decoded.read_chunk_size().unwrap();
            assert_eq!(expected, actual);
        }

        fn read_err(s: &str) {
            let mut decoded = Decoder::new(s.as_bytes());
            let err_kind = decoded.read_chunk_size().unwrap_err().kind();
            assert_eq!(err_kind, io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new(
            "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new(
            "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new(
            "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }
}
<|endoftext|>


<commit_before>use types::{OscPacket, OscType, OscResult, OscMessage, OscMidiMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            let size: usize =
                try!(cursor.read_u32::<BigEndian>()
                           .map_err(OscError::ByteOrderError)) as usize;
            let mut byte_buf: Vec<u8> = Vec::with_capacity(size);
            try!(cursor.take(size as u64)
                       .read_to_end(&mut byte_buf)
                       .map_err(OscError::ReadError));
            pad_cursor(cursor);
            Ok(OscType::Blob(byte_buf))

        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            let opt_char = try!(cursor.read_u32::<BigEndian>()
                                      .map(char::from_u32)
                                      .map_err(OscError::ByteOrderError));
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg("Argument is not a char!".to_string())),
            }
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Remove comment<commit_after>use types::{OscPacket, OscType, OscResult, OscMessage, OscMidiMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            let size: usize =
                try!(cursor.read_u32::<BigEndian>()
                           .map_err(OscError::ByteOrderError)) as usize;
            let mut byte_buf: Vec<u8> = Vec::with_capacity(size);
            try!(cursor.take(size as u64)
                       .read_to_end(&mut byte_buf)
                       .map_err(OscError::ReadError));
            pad_cursor(cursor);
            Ok(OscType::Blob(byte_buf))

        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            let opt_char = try!(cursor.read_u32::<BigEndian>()
                                      .map(char::from_u32)
                                      .map_err(OscError::ByteOrderError));
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg("Argument is not a char!".to_string())),
            }
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>pub fn digit_fact_sum(n: usize) -> usize {
    n.to_string()
     .chars()
     .map(|c| {
         match c {
             '0' => 1,
             '1' => 1,
             '2' => 2,
             '3' => 6,
             '4' => 24,
             '5' => 120,
             '6' => 720,
             '7' => 5040,
             '8' => 40320,
             '9' => 362880,
             _ => panic!(),
         }
     })
     .fold(0, |sum, i| sum + i)
}

pub fn main() {
    let ans = (3..1_000_000)
                  .filter(|&i| i == digit_fact_sum(i))
                  .fold(0, |sum, i| sum + i);
    println!("{}", ans);
}
<commit_msg>update euler34 to more idiomatic rust<commit_after>pub fn digit_fact_sum(n: usize) -> usize {
    n.to_string()
     .chars()
     .map(|c| {
         match c {
             '0' | '1' => 1,
             '2' => 2,
             '3' => 6,
             '4' => 24,
             '5' => 120,
             '6' => 720,
             '7' => 5040,
             '8' => 40320,
             '9' => 362880,
             _ => panic!(),
         }
     })
     .sum()
}

pub fn main() {
    let ans: usize = (3..1_000_000)
                  .filter(|&i| i == digit_fact_sum(i))
                  .sum();
    println!("{}", ans);
}
<|endoftext|>