<commit_before>extern crate rustc_serialize;
extern crate docopt;

extern crate hyper;

use docopt::Docopt;
use rustc_serialize::{Decodable, Decoder};

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

use hyper::Client;
use hyper::header::{Authorization, Bearer};

// TODO: This is only temporary...
const TOKEN: &'static str = "";

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

Usage:
    teller list accounts
    teller show balance <account>
    teller -h | --help
    teller -V | --version

Commands:
    list accounts   List accounts.
    show balance    Show the balance of an account.

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

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_list: bool,
    cmd_accounts: bool,
    cmd_show: bool,
    cmd_balance: bool,
    arg_account: AccountType,
    flag_help: bool,
    flag_version: bool,
}

#[derive(Debug)]
enum AccountType { Current, Savings, Business, Unknown(String), None }

impl Decodable for AccountType {
    fn decode<D: Decoder>(d: &mut D) -> Result<AccountType, D::Error> {
        let s = try!(d.read_str());
        Ok(match &*s {
            "" => AccountType::None,
            "current" => AccountType::Current,
            "savings" => AccountType::Savings,
            "business" => AccountType::Business,
            s => AccountType::Unknown(s.to_string()),
        })
    }
}

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

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

#[derive(Debug, RustcDecodable)]
struct AccountResponse {
    data: Account,
}

#[derive(Debug, RustcDecodable)]
struct AccountsResponse {
    data: Vec<Account>,
}

#[derive(Debug, RustcDecodable)]
struct Account {
    updated_at: String,
    institution: String,
    id: String,
    currency: String,
    balance: String,
    account_number_last_4: String,
}
// TODO: Maybe will need to deserialize with this:
// http://valve.github.io/blog/2014/08/26/json-serialization-in-rust-part-2/

// TODO: Work out when to use matching
//       and when to use try! and when to
//       use something else.

#[derive(Debug)]
enum ConfigError {
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
    JsonStringifyError(rustc_serialize::json::EncoderError),
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "fake display")
    }
}

impl From<io::Error> for ConfigError {
    fn from(e: io::Error) -> ConfigError {
        ConfigError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ConfigError {
    fn from(e: rustc_serialize::json::DecoderError) -> ConfigError {
        ConfigError::JsonParseError(e)
    }
}

impl From<rustc_serialize::json::EncoderError> for ConfigError {
    fn from(e: rustc_serialize::json::EncoderError) -> ConfigError {
        ConfigError::JsonStringifyError(e)
    }
}

impl std::error::Error for ConfigError {
    fn description(&self) -> &str {
        match *self {
            ConfigError::IoError(_) => "I/O Error",
            ConfigError::JsonParseError(_) => "JSON parsing error",
            ConfigError::JsonStringifyError(_) => "JSON stringify error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ConfigError::IoError(ref err) => Some(err as &std::error::Error),
            ConfigError::JsonParseError(ref err) => Some(err as &std::error::Error),
            ConfigError::JsonStringifyError(ref err) => Some(err as &std::error::Error),
        }
    }
}

fn get_config_path() -> PathBuf {
    let fallback_config_path = PathBuf::from("./.tellerrc");
    let append_config_file = |mut p: PathBuf| {
        p.push(".tellerrc");
        p
    };
    env::home_dir().map_or(fallback_config_path, append_config_file)
}

fn get_config_file() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::open(&config_path)
}

fn get_config_file_to_write() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::create(&config_path)
}

fn read_config() -> Result<Config, ConfigError> {
    let mut config_file = try!(get_config_file());

    let mut content_str = String::new();
    try!(config_file.read_to_string(&mut content_str));

    let config: Config = try!(json::decode(&content_str));

    Ok(config)
}

fn write_config(config: &Config) -> Result<(), ConfigError> {
    let mut config_file = try!(get_config_file_to_write());

    let content_str = try!(json::encode(&config));

    try!(config_file.write_all(content_str.as_bytes()));

    Ok(())
}

// TODO: Turns out you've been polluting the namespace really really badly
//       and you're gonna need to fix that!
#[derive(Debug)]
enum ApiServiceError {
    HttpClientError(hyper::error::Error),
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
}

impl std::fmt::Display for ApiServiceError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "fake display")
    }
}

impl From<hyper::error::Error> for ApiServiceError {
    fn from(e: hyper::error::Error) -> ApiServiceError {
        ApiServiceError::HttpClientError(e)
    }
}

impl From<io::Error> for ApiServiceError {
    fn from(e: io::Error) -> ApiServiceError {
        ApiServiceError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ApiServiceError {
    fn from(e: rustc_serialize::json::DecoderError) -> ApiServiceError {
        ApiServiceError::JsonParseError(e)
    }
}

impl std::error::Error for ApiServiceError {
    fn description(&self) -> &str {
        match *self {
            ApiServiceError::HttpClientError(_) => "Api Error",
            ApiServiceError::IoError(_) => "I/O Error",
            ApiServiceError::JsonParseError(_) => "JSON parsing error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ApiServiceError::HttpClientError(ref err) => Some(err as &std::error::Error),
            ApiServiceError::IoError(ref err) => Some(err as &std::error::Error),
            ApiServiceError::JsonParseError(ref err) => Some(err as &std::error::Error),
        }
    }
}

type ApiServiceResult<T> = Result<T, ApiServiceError>;

fn get_accounts() -> ApiServiceResult<AccountsResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(client.get("https://api.teller.io/accounts")
                             .header(auth_header)
                             .send()
                             .and_then(|r| {
                                 if r.status.is_client_error() {
                                     Err(hyper::error::Error::Status)
                                 } else {
                                     Ok(r)
                                 }
                             }));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let accounts_response = try!(json::decode(&body));

    Ok(accounts_response)
}

#[allow(dead_code)]
fn get_account() -> ApiServiceResult<AccountResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(client.get("https://api.teller.io/accounts/4803f712-cc3e-4560-9f80-3be8116d7723")
                             .header(auth_header)
                             .send()
                             .and_then(|r| {
                                if r.status.is_client_error() {
                                    Err(hyper::error::Error::Status)
                                } else {
                                    Ok(r)
                                }
                            }));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let account_response = try!(json::decode(&body));

    Ok(account_response)
}

#[allow(dead_code)]
fn get_account_balance() -> ApiServiceResult<String> {
    get_account().map(|r| r.data.balance)
}

fn main() {
    // TODO: Currently this gets data but it will panic! if no JSON comes back, for example if we
    //       get a 500 server error. (There is no `error` property bizarrely.)
    match get_accounts() {
        Ok(_) => println!("dont print value "),
        Err(why) => println!("error: {}", std::error::Error::description(&why)),
    }

    // get_account_balance();

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

    // TODO: If there is a config file then read it,
    //       otherwise ask a question and write to it.
    let config = match read_config() {
        Ok(config) => config,
        Err(why) => panic!("config could not be read"),
    };
    println!("{}", config.auth_token);

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

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

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

    let _ = write_config(&new_config);

    ()
}
<commit_msg>refactor(error): call description from fmt<commit_after>extern crate rustc_serialize;
extern crate docopt;

extern crate hyper;

use docopt::Docopt;
use rustc_serialize::{Decodable, Decoder};

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

use hyper::Client;
use hyper::header::{Authorization, Bearer};

// TODO: This is only temporary...
const TOKEN: &'static str = "";

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

Usage:
    teller list accounts
    teller show balance <account>
    teller -h | --help
    teller -V | --version

Commands:
    list accounts   List accounts.
    show balance    Show the balance of an account.

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

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_list: bool,
    cmd_accounts: bool,
    cmd_show: bool,
    cmd_balance: bool,
    arg_account: AccountType,
    flag_help: bool,
    flag_version: bool,
}

#[derive(Debug)]
enum AccountType { Current, Savings, Business, Unknown(String), None }

impl Decodable for AccountType {
    fn decode<D: Decoder>(d: &mut D) -> Result<AccountType, D::Error> {
        let s = try!(d.read_str());
        Ok(match &*s {
            "" => AccountType::None,
            "current" => AccountType::Current,
            "savings" => AccountType::Savings,
            "business" => AccountType::Business,
            s => AccountType::Unknown(s.to_string()),
        })
    }
}

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

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

#[derive(Debug, RustcDecodable)]
struct AccountResponse {
    data: Account,
}

#[derive(Debug, RustcDecodable)]
struct AccountsResponse {
    data: Vec<Account>,
}

#[derive(Debug, RustcDecodable)]
struct Account {
    updated_at: String,
    institution: String,
    id: String,
    currency: String,
    balance: String,
    account_number_last_4: String,
}
// TODO: Maybe will need to deserialize with this:
// http://valve.github.io/blog/2014/08/26/json-serialization-in-rust-part-2/

// TODO: Work out when to use matching
//       and when to use try! and when to
//       use something else.

#[derive(Debug)]
enum ConfigError {
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
    JsonStringifyError(rustc_serialize::json::EncoderError),
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.description().fmt(f)
    }
}

impl From<io::Error> for ConfigError {
    fn from(e: io::Error) -> ConfigError {
        ConfigError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ConfigError {
    fn from(e: rustc_serialize::json::DecoderError) -> ConfigError {
        ConfigError::JsonParseError(e)
    }
}

impl From<rustc_serialize::json::EncoderError> for ConfigError {
    fn from(e: rustc_serialize::json::EncoderError) -> ConfigError {
        ConfigError::JsonStringifyError(e)
    }
}

impl std::error::Error for ConfigError {
    fn description(&self) -> &str {
        match *self {
            ConfigError::IoError(_) => "I/O Error",
            ConfigError::JsonParseError(_) => "JSON parsing error",
            ConfigError::JsonStringifyError(_) => "JSON stringify error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ConfigError::IoError(ref err) => Some(err as &std::error::Error),
            ConfigError::JsonParseError(ref err) => Some(err as &std::error::Error),
            ConfigError::JsonStringifyError(ref err) => Some(err as &std::error::Error),
        }
    }
}

fn get_config_path() -> PathBuf {
    let fallback_config_path = PathBuf::from("./.tellerrc");
    let append_config_file = |mut p: PathBuf| {
        p.push(".tellerrc");
        p
    };
    env::home_dir().map_or(fallback_config_path, append_config_file)
}

fn get_config_file() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::open(&config_path)
}

fn get_config_file_to_write() -> Result<File, io::Error> {
    let config_path = get_config_path();
    File::create(&config_path)
}

fn read_config() -> Result<Config, ConfigError> {
    let mut config_file = try!(get_config_file());

    let mut content_str = String::new();
    try!(config_file.read_to_string(&mut content_str));

    let config: Config = try!(json::decode(&content_str));

    Ok(config)
}

fn write_config(config: &Config) -> Result<(), ConfigError> {
    let mut config_file = try!(get_config_file_to_write());

    let content_str = try!(json::encode(&config));

    try!(config_file.write_all(content_str.as_bytes()));

    Ok(())
}

// TODO: Turns out you've been polluting the namespace really really badly
//       and you're gonna need to fix that!
#[derive(Debug)]
enum ApiServiceError {
    HttpClientError(hyper::error::Error),
    IoError(io::Error),
    JsonParseError(rustc_serialize::json::DecoderError),
}

impl std::fmt::Display for ApiServiceError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.description().fmt(f)
    }
}

impl From<hyper::error::Error> for ApiServiceError {
    fn from(e: hyper::error::Error) -> ApiServiceError {
        ApiServiceError::HttpClientError(e)
    }
}

impl From<io::Error> for ApiServiceError {
    fn from(e: io::Error) -> ApiServiceError {
        ApiServiceError::IoError(e)
    }
}

impl From<rustc_serialize::json::DecoderError> for ApiServiceError {
    fn from(e: rustc_serialize::json::DecoderError) -> ApiServiceError {
        ApiServiceError::JsonParseError(e)
    }
}

impl std::error::Error for ApiServiceError {
    fn description(&self) -> &str {
        match *self {
            ApiServiceError::HttpClientError(_) => "Api Error",
            ApiServiceError::IoError(_) => "I/O Error",
            ApiServiceError::JsonParseError(_) => "JSON parsing error",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ApiServiceError::HttpClientError(ref err) => Some(err as &std::error::Error),
            ApiServiceError::IoError(ref err) => Some(err as &std::error::Error),
            ApiServiceError::JsonParseError(ref err) => Some(err as &std::error::Error),
        }
    }
}

type ApiServiceResult<T> = Result<T, ApiServiceError>;

fn get_accounts() -> ApiServiceResult<AccountsResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(client.get("https://api.teller.io/accounts")
                             .header(auth_header)
                             .send()
                             .and_then(|r| {
                                 if r.status.is_client_error() {
                                     Err(hyper::error::Error::Status)
                                 } else {
                                     Ok(r)
                                 }
                             }));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let accounts_response = try!(json::decode(&body));

    Ok(accounts_response)
}

#[allow(dead_code)]
fn get_account() -> ApiServiceResult<AccountResponse> {
    let client = Client::new();

    let auth_header = Authorization(
        Bearer {
            token: TOKEN.to_owned()
        }
    );

    let mut res = try!(client.get("https://api.teller.io/accounts/4803f712-cc3e-4560-9f80-3be8116d7723")
                             .header(auth_header)
                             .send()
                             .and_then(|r| {
                                if r.status.is_client_error() {
                                    Err(hyper::error::Error::Status)
                                } else {
                                    Ok(r)
                                }
                            }));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    println!("Response: {}", body);
    let account_response = try!(json::decode(&body));

    Ok(account_response)
}

#[allow(dead_code)]
fn get_account_balance() -> ApiServiceResult<String> {
    get_account().map(|r| r.data.balance)
}

fn main() {
    // TODO: Currently this gets data but it will panic! if no JSON comes back, for example if we
    //       get a 500 server error. (There is no `error` property bizarrely.)
    match get_accounts() {
        Ok(_) => println!("dont print value "),
        Err(why) => println!("error: {}", std::error::Error::description(&why)),
    }

    // get_account_balance();

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

    // TODO: If there is a config file then read it,
    //       otherwise ask a question and write to it.
    let config = match read_config() {
        Ok(config) => config,
        Err(why) => panic!("config could not be read"),
    };
    println!("{}", config.auth_token);

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

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

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

    let _ = write_config(&new_config);

    ()
}
<|endoftext|>


<commit_before>use config::Config;
use error::Result;
use error::Error;
use ip::IpAddr;
use hyper::Client;
use hyper::header::Connection;
use std::io;
use std::io::prelude::*;
use std::result::Result as StdResult;
use std::str::FromStr;
use regex::Regex;

#[derive(Debug)]
pub enum IpProvider {
    Stdin,
    SfrLaBoxFibre,
}

impl FromStr for IpProvider {
    type Err = String;

    fn from_str(s: &str) -> StdResult<IpProvider, String> {
        match s {
            "-" => Ok(IpProvider::Stdin),
            "sfrlaboxfibre" => Ok(IpProvider::SfrLaBoxFibre),
            _ => Err("Unknown value for IP provider".to_owned()),
        }
    }
}

pub trait IpAddressProvider {
    fn get_my_ip_addr(&self) -> Result<IpAddr>;
}

impl IpAddressProvider {
    pub fn from_config(config: &Config) -> Box<IpAddressProvider + 'static>  {
        match config.ip_provider {
            IpProvider::Stdin => Box::new(StdinIpProvider),
            IpProvider::SfrLaBoxFibre => Box::new(HttpIpProvider),
        }
    }
}

pub struct StdinIpProvider;

impl IpAddressProvider for StdinIpProvider {
    fn get_my_ip_addr(&self) -> Result<IpAddr> {
        let mut input = String::new();

        try!(io::stdin().read_line(&mut input));

        trace!("Read stdin: {}", input);

        let ip_addr = try!(IpAddr::from_str(input.trim()));
        Ok(ip_addr)
    }
}

pub struct HttpIpProvider;

impl IpAddressProvider for HttpIpProvider {
    fn get_my_ip_addr(&self) -> Result<IpAddr> {
        let client = Client::new();

        let mut res = try!(client.get("http://192.168.0.1/")
            .header(Connection::close())
            .send());

        let mut body = String::new();
        try!(res.read_to_string(&mut body));

        trace!("HTTP Response: {}", body);

        let regex = try!(Regex::new(r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))"));

        regex.captures(&*body)
            .and_then(|caps| caps.at(1))
            // Convert Option to Result
            .ok_or(Error::IpNotFound)
            .and_then(|val| IpAddr::from_str(val).map_err(|e| {
                error!("IP parse error: {}", e);
                Error::IpNotFound
            }))
    }
}
<commit_msg>Better error trace when IP provider is unknown<commit_after>use config::Config;
use error::Result;
use error::Error;
use ip::IpAddr;
use hyper::Client;
use hyper::header::Connection;
use std::io;
use std::io::prelude::*;
use std::result::Result as StdResult;
use std::str::FromStr;
use regex::Regex;

#[derive(Debug)]
pub enum IpProvider {
    Stdin,
    SfrLaBoxFibre,
}

impl FromStr for IpProvider {
    type Err = String;

    fn from_str(s: &str) -> StdResult<IpProvider, String> {
        match s {
            "-" => Ok(IpProvider::Stdin),
            "sfrlaboxfibre" => Ok(IpProvider::SfrLaBoxFibre),
            value => Err(format!("Unknown value for IP provider: {}", value).to_owned()),
        }
    }
}

pub trait IpAddressProvider {
    fn get_my_ip_addr(&self) -> Result<IpAddr>;
}

impl IpAddressProvider {
    pub fn from_config(config: &Config) -> Box<IpAddressProvider + 'static>  {
        match config.ip_provider {
            IpProvider::Stdin => Box::new(StdinIpProvider),
            IpProvider::SfrLaBoxFibre => Box::new(HttpIpProvider),
        }
    }
}

pub struct StdinIpProvider;

impl IpAddressProvider for StdinIpProvider {
    fn get_my_ip_addr(&self) -> Result<IpAddr> {
        let mut input = String::new();

        try!(io::stdin().read_line(&mut input));

        trace!("Read stdin: {}", input);

        let ip_addr = try!(IpAddr::from_str(input.trim()));
        Ok(ip_addr)
    }
}

pub struct HttpIpProvider;

impl IpAddressProvider for HttpIpProvider {
    fn get_my_ip_addr(&self) -> Result<IpAddr> {
        let client = Client::new();

        let mut res = try!(client.get("http://192.168.0.1/")
            .header(Connection::close())
            .send());

        let mut body = String::new();
        try!(res.read_to_string(&mut body));

        trace!("HTTP Response: {}", body);

        let regex = try!(Regex::new(r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))"));

        regex.captures(&*body)
            .and_then(|caps| caps.at(1))
            // Convert Option to Result
            .ok_or(Error::IpNotFound)
            .and_then(|val| IpAddr::from_str(val).map_err(|e| {
                error!("IP parse error: {}", e);
                Error::IpNotFound
            }))
    }
}
<|endoftext|>


<commit_before>use address::{Address, Addressable};
use messages;
use protobuf::Message;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket, Ipv4Addr};
use std::fmt::Debug;
use time;

pub trait Serialize {
    fn serialize(&self) -> messages::Node;
}

pub trait Deserialize {
    fn deserialize(message: &messages::Node) -> Self;
}

pub trait Node : Addressable + Debug + Serialize + Send + Sync {
    fn update(&mut self);
    fn send<M: Message>(&self, message: M) where Self : Sized;
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
        self.get_address() == other.get_address()
    }
}

#[derive(Debug)]
pub struct UdpNode {
    address: Address,
    socket_address: SocketAddr,
    last_seen: time::Tm
}

impl UdpNode {
    pub fn new<S: ToSocketAddrs>(address: Address, socket_address: S) -> UdpNode {
        let socket_address = socket_address
            .to_socket_addrs()
            .unwrap()
            .next()
            .unwrap();
        UdpNode {
            address: address,
            socket_address: socket_address,
            last_seen: time::now_utc()
        }
    }
}

impl Node for UdpNode {
    fn update(&mut self) {
        self.last_seen = time::now_utc()
    }

    fn send<M: Message>(&self, message: M) {
        let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
        let ref buf = message.write_to_bytes().unwrap()[..];
        socket.send_to(buf, self.socket_address).unwrap();
    }
}

impl Deserialize for UdpNode {
    fn deserialize(message: &messages::Node) -> UdpNode {
        let ip = message.get_ip_address();
        let ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
        let port = message.get_port() as u16;
        let address = Address::from_str(message.get_id());
        Self::new(address, (ip, port))
    }
}

impl Serialize for UdpNode {
    fn serialize(&self) -> messages::Node {
        let mut message = messages::Node::new();
        message.set_id(self.address.to_str());
        message.set_ip_address(vec![127, 0, 0, 1]); // TODO: use actual IP address
        message.set_port(self.socket_address.port() as u32);
        message
    }
}

impl Addressable for UdpNode {
    fn get_address(&self) -> Address {
        self.address
    }
}

#[cfg(test)]
mod tests {
    use super::{Node, UdpNode};
    use address::Address;

    #[test]
    fn test_update() {
        let address = Address::for_content("some string");
        let mut node = UdpNode::new(address, ("0.0.0.0", 9000));
        let last_seen_before = node.last_seen;
        node.update();
        let last_seen_after = node.last_seen;
        assert!(last_seen_before < last_seen_after);
    }
}
<commit_msg>Alphabetize imports<commit_after>use address::{Address, Addressable};
use messages;
use protobuf::Message;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket, Ipv4Addr};
use std::fmt::Debug;
use time;

pub trait Serialize {
    fn serialize(&self) -> messages::Node;
}

pub trait Deserialize {
    fn deserialize(message: &messages::Node) -> Self;
}

pub trait Node : Addressable + Debug + Serialize + Send + Sync {
    fn update(&mut self);
    fn send<M: Message>(&self, message: M) where Self : Sized;
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
        self.get_address() == other.get_address()
    }
}

#[derive(Debug)]
pub struct UdpNode {
    address: Address,
    socket_address: SocketAddr,
    last_seen: time::Tm
}

impl UdpNode {
    pub fn new<S: ToSocketAddrs>(address: Address, socket_address: S) -> UdpNode {
        let socket_address = socket_address
            .to_socket_addrs()
            .unwrap()
            .next()
            .unwrap();
        UdpNode {
            address: address,
            socket_address: socket_address,
            last_seen: time::now_utc()
        }
    }
}

impl Node for UdpNode {
    fn update(&mut self) {
        self.last_seen = time::now_utc()
    }

    fn send<M: Message>(&self, message: M) {
        let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
        let ref buf = message.write_to_bytes().unwrap()[..];
        socket.send_to(buf, self.socket_address).unwrap();
    }
}

impl Deserialize for UdpNode {
    fn deserialize(message: &messages::Node) -> UdpNode {
        let ip = message.get_ip_address();
        let ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
        let port = message.get_port() as u16;
        let address = Address::from_str(message.get_id());
        Self::new(address, (ip, port))
    }
}

impl Serialize for UdpNode {
    fn serialize(&self) -> messages::Node {
        let mut message = messages::Node::new();
        message.set_id(self.address.to_str());
        message.set_ip_address(vec![127, 0, 0, 1]); // TODO: use actual IP address
        message.set_port(self.socket_address.port() as u32);
        message
    }
}

impl Addressable for UdpNode {
    fn get_address(&self) -> Address {
        self.address
    }
}

#[cfg(test)]
mod tests {
    use address::Address;
    use super::{Node, UdpNode};

    #[test]
    fn test_update() {
        let address = Address::for_content("some string");
        let mut node = UdpNode::new(address, ("0.0.0.0", 9000));
        let last_seen_before = node.last_seen;
        node.update();
        let last_seen_after = node.last_seen;
        assert!(last_seen_before < last_seen_after);
    }
}
<|endoftext|>


<commit_before>use command;
use git;

use std::fs;

#[derive(Debug)]
pub enum Page {
    Open,
    Diff {
        lhs: String,
        rhs: String,
    },
    Commit {
        hash: String,
    },
    FileOrDir {
        relative_path: String,
    },
}

type ErrorMsg = String;
type ParseResult = Result<Page, ErrorMsg>;

struct BrowsePageParser<'a> {
    opts: &'a command::Options,
    git: git::Git<'a>,
}

impl<'a> BrowsePageParser<'a> {
    fn try_parse_commit(&self) -> ParseResult {
        if self.opts.args.len() != 1 {
            return Err("  Invalid number of arguments for commit (1 is expected)".to_string());
        }
        let hash = self.git.hash(&self.opts.args[0])?;
        Ok(Page::Commit {
            hash: hash,
        })
    }

    fn try_parse_diff(&self) -> ParseResult {
        if self.opts.args.len() != 1 {
            return Err("  Invalid number of arguments for diff (1 is expected)".to_string());
        }

        let mut split = self.opts.args[0].splitn(2, "..");
        let lhs = split.next().unwrap();
        let rhs = split.next().ok_or(format!("  Diff format must be specified as LHS..RHS but found {}", self.opts.args[0]))?;

        Ok(Page::Diff {
            lhs: lhs.to_string(),
            rhs: rhs.to_string(),
        })
    }

    fn try_parse_file_or_dir(&self) -> ParseResult {
        if self.opts.args.len() != 1 {
            return Err("  Invalid number of arguments for file or directory (1 is expected)".to_string());
        }

        let path = &self.opts.args[0];

        let entry = fs::canonicalize(path).map_err(|e| format!("  Unable to locate file '{}': {}", path, e))?;
        let relative_path = entry
            .strip_prefix(&self.git.root_dir()?)
            .map_err(|e| format!("  Unable to locate the file in repository: {}", e))?
            .to_str()
            .ok_or("  Failed to convert path into UTF-8 string")?
            .to_string();

        Ok(Page::FileOrDir {
            relative_path: relative_path,
        })
    }
}

pub fn parse_page(opts: &command::Options) -> Result<Page, ErrorMsg> {
    let mut errors = vec!["Error on parsing command line arguments".to_string()];

    let parser = BrowsePageParser {
        opts: opts,
        git: git::new(&opts.git_dir)?,
    };

    if opts.args.is_empty() {
        return Ok(Page::Open)
    }

    match parser.try_parse_file_or_dir() {
        Ok(p) => return Ok(p),
        Err(msg) => errors.push(msg),
    }

    match parser.try_parse_commit() {
        Ok(p) => return Ok(p),
        Err(msg) => errors.push(msg),
    }

    match parser.try_parse_diff() {
        Ok(p) => return Ok(p),
        Err(msg) => errors.push(msg),
    }

    Err(errors.join("\n"))
}
<commit_msg>diff must have higher priority than commit<commit_after>use command;
use git;

use std::fs;

#[derive(Debug)]
pub enum Page {
    Open,
    Diff {
        lhs: String,
        rhs: String,
    },
    Commit {
        hash: String,
    },
    FileOrDir {
        relative_path: String,
    },
}

type ErrorMsg = String;
type ParseResult = Result<Page, ErrorMsg>;

struct BrowsePageParser<'a> {
    opts: &'a command::Options,
    git: git::Git<'a>,
}

impl<'a> BrowsePageParser<'a> {
    fn try_parse_commit(&self) -> ParseResult {
        if self.opts.args.len() != 1 {
            return Err("  Invalid number of arguments for commit (1 is expected)".to_string());
        }
        let hash = self.git.hash(&self.opts.args[0])?;
        Ok(Page::Commit {
            hash: hash,
        })
    }

    fn try_parse_diff(&self) -> ParseResult {
        if self.opts.args.len() != 1 {
            return Err("  Invalid number of arguments for diff (1 is expected)".to_string());
        }

        let mut split = self.opts.args[0].splitn(2, "..");
        let lhs = split.next().unwrap();
        let rhs = split.next().ok_or(format!("  Diff format must be specified as LHS..RHS but found {}", self.opts.args[0]))?;

        Ok(Page::Diff {
            lhs: self.git.hash(&lhs)?,
            rhs: self.git.hash(&rhs)?,
        })
    }

    fn try_parse_file_or_dir(&self) -> ParseResult {
        if self.opts.args.len() != 1 {
            return Err("  Invalid number of arguments for file or directory (1 is expected)".to_string());
        }

        let path = &self.opts.args[0];

        let entry = fs::canonicalize(path).map_err(|e| format!("  Unable to locate file '{}': {}", path, e))?;
        let relative_path = entry
            .strip_prefix(&self.git.root_dir()?)
            .map_err(|e| format!("  Unable to locate the file in repository: {}", e))?
            .to_str()
            .ok_or("  Failed to convert path into UTF-8 string")?
            .to_string();

        Ok(Page::FileOrDir {
            relative_path: relative_path,
        })
    }
}

pub fn parse_page(opts: &command::Options) -> Result<Page, ErrorMsg> {
    let mut errors = vec!["Error on parsing command line arguments".to_string()];

    let parser = BrowsePageParser {
        opts: opts,
        git: git::new(&opts.git_dir)?,
    };

    if opts.args.is_empty() {
        return Ok(Page::Open)
    }

    match parser.try_parse_file_or_dir() {
        Ok(p) => return Ok(p),
        Err(msg) => errors.push(msg),
    }

    match parser.try_parse_diff() {
        Ok(p) => return Ok(p),
        Err(msg) => errors.push(msg),
    }

    match parser.try_parse_commit() {
        Ok(p) => return Ok(p),
        Err(msg) => errors.push(msg),
    }

    Err(errors.join("\n"))
}
<|endoftext|>


<commit_before>extern crate futures;
#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::{File, read_dir};
use std::io::{self, Read};
use std::time::Instant;

use futures::Async;

use iron::mime::Mime;
use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use serde_json::Value;

use staticfile::Static;

use mount::Mount;

use gluon::base::symbol::{Symbol, SymbolRef};
use gluon::base::kind::{ArcKind, KindEnv};
use gluon::base::types::{Alias, ArcType, TypeEnv};
use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::internal::ValuePrinter;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct EmptyEnv;

impl KindEnv for EmptyEnv {
    fn find_kind(&self, _type_name: &SymbolRef) -> Option<ArcKind> {
        None
    }
}

impl TypeEnv for EmptyEnv {
    fn find_type(&self, _id: &SymbolRef) -> Option<&ArcType> {
        None
    }
    fn find_type_info(&self, _id: &SymbolRef) -> Option<&Alias<Symbol, ArcType>> {
        None
    }
    fn find_record(&self, _fields: &[Symbol]) -> Option<(ArcType, ArcType)> {
        None
    }
}

pub struct VMKey;

impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| {
        let mime: Mime = "text/plain".parse().unwrap();

        Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
    })
}

fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);

    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    {
        let mut context = vm.context();

        // Prevent the stack from consuming to much memory
        context.set_max_stack_size(10000);

        // Prevent infinite loops from running forever
        let start = Instant::now();
        context.set_hook(Some(Box::new(move |_, _| if start.elapsed().as_secs() < 10 {
            Ok(Async::Ready(()))
        } else {
            Err(Error::Message("Thread has exceeded the allowed exection time".into()))
        })));
    }

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };

    unsafe {
        Ok(format!("{} : {}",
                   ValuePrinter::new(&EmptyEnv, &typ, value.get_value()).max_level(6),
                   typ))
    }
}

pub struct Examples;

impl Key for Examples {
    type Value = String;
}

fn examples(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Examples>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

/// Load all examples into a JSON array `[{ name: .., value: .. }, ..]`
fn load_examples() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![("name".into(), Value::String(name)),
                             ("value".into(), Value::String(contents))];

            Ok(Value::Object(value.into_iter().collect()))
        })
        .collect::<io::Result<_>>()
        .unwrap();

    Value::Array(vec)
}

fn make_eval_vm() -> RootedThread {
    let vm = RootedThread::new();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let import = Import::new(DefaultImporter);
        import.paths.write().unwrap().clear();
        vm.get_macros()
            .insert(String::from("import"), import);
    }

    // Initialize the basic types such as `Bool` and `Option` so they are available when loading
    // other modules
    Compiler::new()
        .implicit_prelude(false)
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import! "std/types.glu" "#)
        .unwrap();

    gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
    // Load the io library so the prelude can be loaded (`IO` actions won't actually execute however)
    gluon::io::load(&vm).expect("Loaded IO library");

    vm
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("dist"));

    {
        let mut middleware = Chain::new(eval);

        let vm = make_eval_vm();
        middleware.link(persistent::Read::<VMKey>::both(vm));

        mount.mount("/eval", middleware);
    }

    {
        let mut middleware = Chain::new(examples);
        let examples_string = serde_json::to_string(&load_examples()).unwrap();

        middleware.link(persistent::Read::<Examples>::both(examples_string));
        mount.mount("/examples", middleware);
    }

    let address = "0.0.0.0:8080";

    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(mount).http(address).unwrap();

    println!("Server started at `{}`", address);
}
<commit_msg>style: Run rustfmt<commit_after>extern crate futures;
#[macro_use]
extern crate iron;
extern crate persistent;
extern crate staticfile;
extern crate mount;
extern crate gluon;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate env_logger;

use std::fs::{File, read_dir};
use std::io::{self, Read};
use std::time::Instant;

use futures::Async;

use iron::mime::Mime;
use iron::prelude::*;
use iron::status;
use iron::typemap::Key;

use serde_json::Value;

use staticfile::Static;

use mount::Mount;

use gluon::base::symbol::{Symbol, SymbolRef};
use gluon::base::kind::{ArcKind, KindEnv};
use gluon::base::types::{Alias, ArcType, TypeEnv};
use gluon::vm::thread::{RootedThread, Thread, ThreadInternal};
use gluon::vm::Error;
use gluon::vm::internal::ValuePrinter;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::Compiler;
use gluon::import::{DefaultImporter, Import};

pub struct EmptyEnv;

impl KindEnv for EmptyEnv {
    fn find_kind(&self, _type_name: &SymbolRef) -> Option<ArcKind> {
        None
    }
}

impl TypeEnv for EmptyEnv {
    fn find_type(&self, _id: &SymbolRef) -> Option<&ArcType> {
        None
    }
    fn find_type_info(&self, _id: &SymbolRef) -> Option<&Alias<Symbol, ArcType>> {
        None
    }
    fn find_record(&self, _fields: &[Symbol]) -> Option<(ArcType, ArcType)> {
        None
    }
}

pub struct VMKey;

impl Key for VMKey {
    type Value = RootedThread;
}

fn eval(req: &mut Request) -> IronResult<Response> {
    eval_(req).map(|s| {
        let mime: Mime = "text/plain".parse().unwrap();

        Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
    })
}

fn eval_(req: &mut Request) -> IronResult<String> {
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Eval: `{}`", body);

    let global_vm = req.get::<persistent::Read<VMKey>>().unwrap();
    let vm = match global_vm.new_thread() {
        Ok(vm) => vm,
        Err(err) => return Ok(format!("{}", err)),
    };

    // Prevent a single thread from allocating to much memory
    vm.set_memory_limit(2_000_000);

    {
        let mut context = vm.context();

        // Prevent the stack from consuming to much memory
        context.set_max_stack_size(10000);

        // Prevent infinite loops from running forever
        let start = Instant::now();
        context.set_hook(Some(
            Box::new(move |_, _| if start.elapsed().as_secs() < 10 {
                Ok(Async::Ready(()))
            } else {
                Err(Error::Message(
                    "Thread has exceeded the allowed exection time".into(),
                ))
            }),
        ));
    }

    let (value, typ) = match Compiler::new()
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "<top>", &body) {
        Ok(value) => value,
        Err(err) => return Ok(format!("{}", err)),
    };

    unsafe {
        Ok(format!(
            "{} : {}",
            ValuePrinter::new(&EmptyEnv, &typ, value.get_value()).max_level(6),
            typ
        ))
    }
}

pub struct Examples;

impl Key for Examples {
    type Value = String;
}

fn examples(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Examples>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

/// Load all examples into a JSON array `[{ name: .., value: .. }, ..]`
fn load_examples() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![
                ("name".into(), Value::String(name)),
                ("value".into(), Value::String(contents)),
            ];

            Ok(Value::Object(value.into_iter().collect()))
        })
        .collect::<io::Result<_>>()
        .unwrap();

    Value::Array(vec)
}

fn make_eval_vm() -> RootedThread {
    let vm = RootedThread::new();

    // Ensure the import macro cannot be abused to to open files
    {
        // Ensure the lock to `paths` are released
        let import = Import::new(DefaultImporter);
        import.paths.write().unwrap().clear();
        vm.get_macros().insert(String::from("import"), import);
    }

    // Initialize the basic types such as `Bool` and `Option` so they are available when loading
    // other modules
    Compiler::new()
        .implicit_prelude(false)
        .run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "", r#" import! "std/types.glu" "#)
        .unwrap();

    gluon::vm::primitives::load(&vm).expect("Loaded primitives library");
    // Load the io library so the prelude can be loaded
    // (`IO` actions won't actually execute however)
    gluon::io::load(&vm).expect("Loaded IO library");

    vm
}

fn main() {
    env_logger::init().unwrap();
    let mut mount = Mount::new();

    mount.mount("/", Static::new("dist"));

    {
        let mut middleware = Chain::new(eval);

        let vm = make_eval_vm();
        middleware.link(persistent::Read::<VMKey>::both(vm));

        mount.mount("/eval", middleware);
    }

    {
        let mut middleware = Chain::new(examples);
        let examples_string = serde_json::to_string(&load_examples()).unwrap();

        middleware.link(persistent::Read::<Examples>::both(examples_string));
        mount.mount("/examples", middleware);
    }

    let address = "0.0.0.0:8080";

    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(mount).http(address).unwrap();

    println!("Server started at `{}`", address);
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::io::Read;
use std::fmt;
use std::cmp;
use std::io;

const DEFAULT_NUMBER_OF_SAMPLES:usize = 31;
const DEFAULT_NUMBER_OF_ROWS_PER_PATTERN:usize = 64;
const DEFAULT_NUMBER_OF_CHANNELS_PER_ROW:usize = 4;
const MAGIC_MK:[u8; 4] =['M' as u8, '.' as u8, 'K' as u8, '.' as u8];

#[derive(Debug)]
pub struct SampleInfo {
	pub name: String, // [char; 22],
	pub length: u16, // In words, so multiply by 2
	pub finetune: u8,
	pub volume: u8, // 0-64
	pub repeat_start: u16, // In words from start of sample data, so multiply by 2
	pub repeat_length: u16, // Number of words to loop, multiply by 2
}

impl SampleInfo {
	pub fn new() -> SampleInfo {
		SampleInfo{name: String::new(), length:0, finetune:0, volume:0, repeat_start:0, repeat_length:0}
	}
}

#[derive(Debug)]
pub struct Channel {
	pub period: u16, // Really u12
	pub sample_number: u8,
	pub effect: u16 // Really u12
}

impl Channel {
	pub fn new() -> Channel {
		Channel{period: 0, sample_number: 0, effect: 0}
	}
}

#[derive(Debug)]
pub struct Row {
	pub channels: Vec<Channel>
}

impl Row {
	pub fn new() -> Row {
		let mut row = Row{channels: Vec::new()};
		for _ in 0..DEFAULT_NUMBER_OF_CHANNELS_PER_ROW {
			row.channels.push(Channel::new());
		}

		row
	}
}

#[derive(Debug)]
pub struct Pattern {
	pub rows: Vec<Row>
}

impl Pattern {
	pub fn new() -> Pattern {
		let mut p = Pattern{rows: Vec::new()};

		for _ in 0..DEFAULT_NUMBER_OF_ROWS_PER_PATTERN {
			p.rows.push(Row::new());
		}

		p
	}
}

pub struct Positions {
	pub data: [u8; 128]
}

impl fmt::Debug for Positions {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.data[..].fmt(formatter)
    }
}

#[derive(Debug)]
pub struct PTModule {
	pub name: String, // [char; 20],
	pub sample_info: Vec<SampleInfo>, // [SampleInfo; DEFAULT_NUMBER_OF_SAMPLES]
	pub length: u8, // Length 1-128
	pub nt_restart: u8, // Set to 127
	pub positions: Positions, // The order in which to play patterns
	pub mk: [u8; 4], // Set to M.K.
	pub patterns: Vec<Pattern>,
	pub sample_data: Vec<Vec<u8>> // The bytes in the samples -127 - 127
}

impl PTModule {
	pub fn new() -> PTModule {
		let mut ptmod = PTModule{name: String::new(), sample_info: Vec::new(), length:0,
			nt_restart: 127, positions: Positions{data: [0; 128]}, mk: MAGIC_MK,
			patterns: Vec::new(), sample_data: Vec::new() };

		for _ in 0..DEFAULT_NUMBER_OF_SAMPLES {
			ptmod.sample_info.push(SampleInfo::new());
		}

		ptmod
	}
}

fn read_all(reader: &mut Read, data: &mut [u8]) -> io::Result<usize> {
	let mut pos = 0;
	while pos < data.len() {
		let slice = &mut data[pos..];
		let n = try!(reader.read(slice));
		pos += n;
	}

	Ok(pos)
}

fn write_or_panic(writer: &mut Write, data: &[u8]) {
	match writer.write_all(&data) {
		Ok(_) => (),
		_ => panic!("Failed to write bytes")
	};
}

fn read_0_padded_string(reader: &mut Read, len: usize) -> String {
	let mut data = vec![0u8; len];
	read_all(reader,&mut data);
	let mut str = String::new();
	for byte in data {
		if byte != 0 {
			str.push(byte as char);
		}
	}

	str
}

fn write_0_padded_string(writer: &mut Write, str: &String, len: usize) {
	let mut data = vec![0u8; len];
	let str_buf = str.as_bytes();
	let m = cmp::min(data.len(),str_buf.len());
	for i in 0..m {
		data[i] = str_buf[i];
	}

	write_or_panic(writer, &data);
}

fn read_big_endian_u16(reader: &mut Read) -> u16 {
	let mut data_arr = [0u8; 2];
	read_all(reader,&mut data_arr);

	let mut data:u16 = 0;

	for n in data_arr.iter() {
		data = (data << 8) + *n as u16;
	}

	data
}

fn write_big_endian_u16(writer: &mut Write, val: u16) {
	let mut data = [0u8; 2];
	data[0] = (val >> 8) as u8;
	data[1] = (val & 0xff) as u8;

	write_or_panic(writer, &data);
}

fn read_u8(reader: &mut Read) -> u8 {
	let mut data = [0u8; 1];

	read_all(reader, &mut data);

	data[0]
}

fn write_u8(writer: &mut Write, val: u8) {
	let mut data = [0u8; 1];
	data[0] = val;

	write_or_panic(writer, &data);
}

/// Write a 31 sample Amiga ProTracker mod-file
/// Panics on all errors
pub fn write_mod(writer: &mut Write, module: &mut PTModule) {

	// First write songname, 20 bytes, pad with 0
	write_0_padded_string(writer,&module.name,20);
	// Then write all 32 samples
	// TODO Handle the case when the vector has less than 31 samples
	let mut num_samples = 0;
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let ref si = module.sample_info[i];
		// Sample name
		write_0_padded_string(writer, &si.name, 22);
		// Sample length
		write_big_endian_u16(writer, si.length);
		if si.length > 0 {
			num_samples += 1;
		}
		// Finetune
		write_u8(writer, si.finetune);
		// Volume
		write_u8(writer, si.volume);
		// Repeat start
		write_big_endian_u16(writer, si.repeat_start);
		// Repeat length
		write_big_endian_u16(writer, si.repeat_length);
	}

	let num_samples = num_samples;
	// Songlength
	write_u8(writer, module.length);
	// nt_restart
	write_u8(writer, module.nt_restart);
	// Song positions
	write_or_panic(writer,&module.positions.data);
	// M.K.
	write_or_panic(writer,&module.mk);

	// All patterns
	for pattern_it in module.patterns.iter() {
		// All rows
		for row_it in pattern_it.rows.iter() {
			// All channels
			for channel_it in row_it.channels.iter() {
				let mut data = [0u8; 4];

				data[0] = (channel_it.sample_number & 0xf0) | ((channel_it.period & 0xf00) >> 8) as u8;
				data[1] = (channel_it.period & 0xff) as u8;
				data[2] = ((channel_it.sample_number & 0x0f) << 4) | ((channel_it.effect & 0xf00) >> 8) as u8;
				data[3] = (channel_it.effect & 0xff) as u8;

				write_or_panic(writer,&data);
			}
		}
	}

	// And finally all samples
	for sample_it in module.sample_data.iter() {
		write_or_panic(writer,sample_it);
	}

	if num_samples != module.sample_data.len() {
		panic!("Warning! Number of samples does not match sample data");
	}
}

/// Read a 31 sample Amiga ProTracker mod-file
/// Panics on all errors
pub fn read_mod(reader: &mut Read) -> PTModule {
	let mut module = PTModule::new();

	// First read 20 bytes songname
	module.name = read_0_padded_string(reader, 20);
	// Read all sample info
	// TODO Handle 15 sample files
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let si = &mut module.sample_info[i];
		// Sample name
		si.name = read_0_padded_string(reader, 22);
		si.length = read_big_endian_u16(reader);
		// Finetune
		si.finetune = read_u8(reader);
		// Volume
		si.volume = read_u8(reader);
		// Repeat start
		si.repeat_start = read_big_endian_u16(reader);
		// Repeat length
		si.repeat_length = read_big_endian_u16(reader);
	}

	// Songlength
	module.length = read_u8(reader);
	// nt_restart
	module.nt_restart = read_u8(reader);
	// Song positions
	read_all(reader,&mut module.positions.data);
	// M.K.
	read_all(reader,&mut module.mk);
	if module.mk != MAGIC_MK {
		panic!("Unknown format {:?}", module.mk);
	}

	// Read all patterns
	let mut num_patterns = 0;
	for n in module.positions.data.iter() {
		num_patterns = cmp::max(num_patterns,*n);
	}
	num_patterns += 1;
	for _ in 0..num_patterns {
		let mut pattern = Pattern::new();
		for mut row in &mut pattern.rows {
			for channel in &mut row.channels {
				let mut data  = [0u8;4];
				read_all(reader,&mut data);
				channel.sample_number = (data[0] & 0xf0) | ((data[2] & 0xf0) >> 4);
				channel.period = (((data[0] & 0x0f) as u16) << 8) | (data[1] as u16);
				channel.effect = (((data[2] & 0x0f) as u16) << 8) | (data[3] as u16);
			}
		}
		module.patterns.push(pattern);
	}

	// Read all samples
	for si in &module.sample_info {
		if si.length > 0 {
			let length_in_bytes = si.length * 2;
			let mut data = vec![0u8; length_in_bytes as usize];
			read_all(reader,&mut data);
			module.sample_data.push(data);
		}
	}

	// Now we have read all data.
	// Sanity check that the reader is empty
	let mut data = [0u8; 1];
	match reader.read(&mut data) {
		Ok(n) if n == data.len() => panic!("Unread data left in file"),
		_ => ()
	};

	module
}
<commit_msg>Removed more panic<commit_after>use std::io::Write;
use std::io::Read;
use std::fmt;
use std::cmp;
use std::io;

const DEFAULT_NUMBER_OF_SAMPLES:usize = 31;
const DEFAULT_NUMBER_OF_ROWS_PER_PATTERN:usize = 64;
const DEFAULT_NUMBER_OF_CHANNELS_PER_ROW:usize = 4;
const MAGIC_MK:[u8; 4] =['M' as u8, '.' as u8, 'K' as u8, '.' as u8];

#[derive(Debug)]
pub struct SampleInfo {
	pub name: String, // [char; 22],
	pub length: u16, // In words, so multiply by 2
	pub finetune: u8,
	pub volume: u8, // 0-64
	pub repeat_start: u16, // In words from start of sample data, so multiply by 2
	pub repeat_length: u16, // Number of words to loop, multiply by 2
}

impl SampleInfo {
	pub fn new() -> SampleInfo {
		SampleInfo{name: String::new(), length:0, finetune:0, volume:0, repeat_start:0, repeat_length:0}
	}
}

#[derive(Debug)]
pub struct Channel {
	pub period: u16, // Really u12
	pub sample_number: u8,
	pub effect: u16 // Really u12
}

impl Channel {
	pub fn new() -> Channel {
		Channel{period: 0, sample_number: 0, effect: 0}
	}
}

#[derive(Debug)]
pub struct Row {
	pub channels: Vec<Channel>
}

impl Row {
	pub fn new() -> Row {
		let mut row = Row{channels: Vec::new()};
		for _ in 0..DEFAULT_NUMBER_OF_CHANNELS_PER_ROW {
			row.channels.push(Channel::new());
		}

		row
	}
}

#[derive(Debug)]
pub struct Pattern {
	pub rows: Vec<Row>
}

impl Pattern {
	pub fn new() -> Pattern {
		let mut p = Pattern{rows: Vec::new()};

		for _ in 0..DEFAULT_NUMBER_OF_ROWS_PER_PATTERN {
			p.rows.push(Row::new());
		}

		p
	}
}

pub struct Positions {
	pub data: [u8; 128]
}

impl fmt::Debug for Positions {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.data[..].fmt(formatter)
    }
}

#[derive(Debug)]
pub struct PTModule {
	pub name: String, // [char; 20],
	pub sample_info: Vec<SampleInfo>, // [SampleInfo; DEFAULT_NUMBER_OF_SAMPLES]
	pub length: u8, // Length 1-128
	pub nt_restart: u8, // Set to 127
	pub positions: Positions, // The order in which to play patterns
	pub mk: [u8; 4], // Set to M.K.
	pub patterns: Vec<Pattern>,
	pub sample_data: Vec<Vec<u8>> // The bytes in the samples -127 - 127
}

impl PTModule {
	pub fn new() -> PTModule {
		let mut ptmod = PTModule{name: String::new(), sample_info: Vec::new(), length:0,
			nt_restart: 127, positions: Positions{data: [0; 128]}, mk: MAGIC_MK,
			patterns: Vec::new(), sample_data: Vec::new() };

		for _ in 0..DEFAULT_NUMBER_OF_SAMPLES {
			ptmod.sample_info.push(SampleInfo::new());
		}

		ptmod
	}
}

fn read_all(reader: &mut Read, data: &mut [u8]) -> io::Result<usize> {
	let mut pos = 0;
	while pos < data.len() {
		let slice = &mut data[pos..];
		let n = try!(reader.read(slice));
		pos += n;
	}

	Ok(pos)
}

fn write_or_panic(writer: &mut Write, data: &[u8]) {
	match writer.write_all(&data) {
		Ok(_) => (),
		_ => panic!("Failed to write bytes")
	};
}

fn read_0_padded_string(reader: &mut Read, len: usize) -> Result<String, io::Error> {
	let mut data = vec![0u8; len];
	try!(read_all(reader,&mut data));
	let mut str = String::new();
	for byte in data {
		if byte != 0 {
			str.push(byte as char);
		}
	}

	Ok(str)
}

fn write_0_padded_string(writer: &mut Write, str: &String, len: usize) {
	let mut data = vec![0u8; len];
	let str_buf = str.as_bytes();
	let m = cmp::min(data.len(),str_buf.len());
	for i in 0..m {
		data[i] = str_buf[i];
	}

	write_or_panic(writer, &data);
}

fn read_big_endian_u16(reader: &mut Read) -> Result<u16, io::Error> {
	let mut data_arr = [0u8; 2];
	try!(read_all(reader,&mut data_arr));

	let mut data:u16 = 0;

	for n in data_arr.iter() {
		data = (data << 8) + *n as u16;
	}

	Ok(data)
}

fn write_big_endian_u16(writer: &mut Write, val: u16) {
	let mut data = [0u8; 2];
	data[0] = (val >> 8) as u8;
	data[1] = (val & 0xff) as u8;

	write_or_panic(writer, &data);
}

fn read_u8(reader: &mut Read) -> Result<u8, io::Error> {
	let mut data = [0u8; 1];

	try!(read_all(reader, &mut data));

	Ok(data[0])
}

fn write_u8(writer: &mut Write, val: u8) {
	let mut data = [0u8; 1];
	data[0] = val;

	write_or_panic(writer, &data);
}

/// Write a 31 sample Amiga ProTracker mod-file
/// Panics on all errors
pub fn write_mod(writer: &mut Write, module: &mut PTModule) {

	// First write songname, 20 bytes, pad with 0
	write_0_padded_string(writer,&module.name,20);
	// Then write all 32 samples
	// TODO Handle the case when the vector has less than 31 samples
	let mut num_samples = 0;
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let ref si = module.sample_info[i];
		// Sample name
		write_0_padded_string(writer, &si.name, 22);
		// Sample length
		write_big_endian_u16(writer, si.length);
		if si.length > 0 {
			num_samples += 1;
		}
		// Finetune
		write_u8(writer, si.finetune);
		// Volume
		write_u8(writer, si.volume);
		// Repeat start
		write_big_endian_u16(writer, si.repeat_start);
		// Repeat length
		write_big_endian_u16(writer, si.repeat_length);
	}

	let num_samples = num_samples;
	// Songlength
	write_u8(writer, module.length);
	// nt_restart
	write_u8(writer, module.nt_restart);
	// Song positions
	write_or_panic(writer,&module.positions.data);
	// M.K.
	write_or_panic(writer,&module.mk);

	// All patterns
	for pattern_it in module.patterns.iter() {
		// All rows
		for row_it in pattern_it.rows.iter() {
			// All channels
			for channel_it in row_it.channels.iter() {
				let mut data = [0u8; 4];

				data[0] = (channel_it.sample_number & 0xf0) | ((channel_it.period & 0xf00) >> 8) as u8;
				data[1] = (channel_it.period & 0xff) as u8;
				data[2] = ((channel_it.sample_number & 0x0f) << 4) | ((channel_it.effect & 0xf00) >> 8) as u8;
				data[3] = (channel_it.effect & 0xff) as u8;

				write_or_panic(writer,&data);
			}
		}
	}

	// And finally all samples
	for sample_it in module.sample_data.iter() {
		write_or_panic(writer,sample_it);
	}

	if num_samples != module.sample_data.len() {
		panic!("Warning! Number of samples does not match sample data");
	}
}

/// Read a 31 sample Amiga ProTracker mod-file
/// Panics on all errors
pub fn read_mod(reader: &mut Read) -> Result<PTModule, io::Error> {
	let mut module = PTModule::new();

	// First read 20 bytes songname
	module.name = try!(read_0_padded_string(reader, 20));
	// Read all sample info
	// TODO Handle 15 sample files
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let si = &mut module.sample_info[i];
		// Sample name
		si.name = try!(read_0_padded_string(reader, 22));
		si.length = try!(read_big_endian_u16(reader));
		// Finetune
		si.finetune = try!(read_u8(reader));
		// Volume
		si.volume = try!(read_u8(reader));
		// Repeat start
		si.repeat_start = try!(read_big_endian_u16(reader));
		// Repeat length
		si.repeat_length = try!(read_big_endian_u16(reader));
	}

	// Songlength
	module.length = try!(read_u8(reader));
	// nt_restart
	module.nt_restart = try!(read_u8(reader));
	// Song positions
	try!(read_all(reader,&mut module.positions.data));
	// M.K.
	try!(read_all(reader,&mut module.mk));
	if module.mk != MAGIC_MK {
		panic!("Unknown format {:?}", module.mk);
	}

	// Read all patterns
	let mut num_patterns = 0;
	for n in module.positions.data.iter() {
		num_patterns = cmp::max(num_patterns,*n);
	}
	num_patterns += 1;
	for _ in 0..num_patterns {
		let mut pattern = Pattern::new();
		for mut row in &mut pattern.rows {
			for channel in &mut row.channels {
				let mut data  = [0u8;4];
				try!(read_all(reader,&mut data));
				channel.sample_number = (data[0] & 0xf0) | ((data[2] & 0xf0) >> 4);
				channel.period = (((data[0] & 0x0f) as u16) << 8) | (data[1] as u16);
				channel.effect = (((data[2] & 0x0f) as u16) << 8) | (data[3] as u16);
			}
		}
		module.patterns.push(pattern);
	}

	// Read all samples
	for si in &module.sample_info {
		if si.length > 0 {
			let length_in_bytes = si.length * 2;
			let mut data = vec![0u8; length_in_bytes as usize];
			try!(read_all(reader,&mut data));
			module.sample_data.push(data);
		}
	}

	// Now we have read all data.
	// Sanity check that the reader is empty
	let mut data = [0u8; 1];
	match reader.read(&mut data) {
		Ok(n) if n == data.len() => panic!("Unread data left in file"),
		_ => ()
	};

	Ok(module)
}
<|endoftext|>


<commit_before>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge{count: count, states: states}
    }
}

impl Iterator for Merge  {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> Option<u32> {
        if let Ok(i) = v.parse::<u32>() {
            Some(i)
        } else {
            None
        }
    };
    let values = matches.map(move |s| {
        let numbers = s.split(',').filter_map(|v| to_int(&v));
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }

    fn merge(filename: &str) -> (Vec<u32>, Vec<u32>) {
        let result = Merge::new(filename).collect::<Vec<u32>>();
        let output = get_output(filename).unwrap().collect::<Vec<u32>>();
        (result, output)
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (result, output) = merge(filename);
        assert_eq!(result, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (result, output) = merge(filename);
        assert_eq!(output.len(), 0);
        assert_eq!(result.len(), 0);
        assert_eq!(result, output);
    }
}
<commit_msg>Large file works. But is it lazy<commit_after>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge{count: count, states: states}
    }
}

impl Iterator for Merge  {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> Option<u32> {
        if let Ok(i) = v.parse::<u32>() {
            Some(i)
        } else {
            None
        }
    };
    let values = matches.map(move |s| {
        let numbers = s.split(',').filter_map(|v| to_int(&v));
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }

    fn merge(filename: &str) -> (Vec<u32>, Vec<u32>) {
        let result = Merge::new(filename).collect::<Vec<u32>>();
        let output = get_output(filename).unwrap().collect::<Vec<u32>>();
        (result, output)
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (result, output) = merge(filename);
        assert_eq!(result, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (result, output) = merge(filename);
        assert_eq!(output.len(), 0);
        assert_eq!(result.len(), 0);
        assert_eq!(result, output);
    }

    #[test]
    fn test_err() {
        let filename = "../data/err.txt";
        let (result, output) = merge(filename);
        assert_ne!(result, output);
    }
}
<|endoftext|>