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

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

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

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

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

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

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

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

extern crate notify;

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

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

use std::path::Path;

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

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

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

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

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

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

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

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

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

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

    let (tx_watcher, rx_watcher) = channel();
    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx_watcher, Duration::from_secs(1)));
    try!(watcher.watch(config_file, RecursiveMode::Recursive));
    loop {
        match rx_watcher.recv() {
            Ok(event) => {
                info!("{:?}", event);
            },
            Err(e) => error!("watch error: {:?}", e),
        }
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

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

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

extern crate notify;

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

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

use std::path::Path;

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

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

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

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

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

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

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

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

        // Initialize Iron to process requests
        let mut _iron = try!(Iron::new(chain).http((host.as_ref(), port_number)));
        info!("Haxonite running on port: {}!", port_number);
        if let Some(ref rx_server) = rx_server {
        info!("RECEIVER: {:?}!", rx_server);
            match rx_server.recv() {
                Ok(_) => continue,
                Err(_) => break
            }
        }
    }
    Ok(())
}

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

    let (tx_watcher, rx_watcher) = channel();
    let (tx_server, rx_server) = channel();
    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx_watcher, Duration::from_secs(1)));
    try!(watcher.watch(config_file, RecursiveMode::Recursive));
    try!(serve(matches, Some(rx_server)));
    loop {
        match rx_watcher.recv() {
            Ok(event) => {
                info!("{:?}", event);
                tx_server.send("reload");
            },
            Err(e) => error!("watch error: {:?}", e),
        }
    }
}

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

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

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

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

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

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

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

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


<commit_before>extern crate core;
extern crate iron;
extern crate mount;
extern crate rustc_serialize;
extern crate staticfile;
extern crate toml;
extern crate url;

use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;

use iron::prelude::*;
use mount::Mount;
use staticfile::Static;

mod api;
mod collection;
mod error;
mod vfs;

use api::*;
use collection::*;

fn main() {

    let mut collection = Collection::new();
    collection.load_config(Path::new("Polaris.toml")).unwrap();

    let collection = Arc::new(Mutex::new(collection));

    let mut mount = Mount::new();
    let api_handler = get_api_handler(collection);
    mount.mount("/api/", api_handler);
    mount.mount("/", Static::new(Path::new("web")));

    Iron::new(mount).http("localhost:3000").unwrap();
}
<commit_msg>Added missing crate<commit_after>extern crate core;
extern crate iron;
extern crate mount;
extern crate regex;
extern crate rustc_serialize;
extern crate staticfile;
extern crate toml;
extern crate url;

use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;

use iron::prelude::*;
use mount::Mount;
use staticfile::Static;

mod api;
mod collection;
mod error;
mod vfs;

use api::*;
use collection::*;

fn main() {

    let mut collection = Collection::new();
    collection.load_config(Path::new("Polaris.toml")).unwrap();

    let collection = Arc::new(Mutex::new(collection));

    let mut mount = Mount::new();
    let api_handler = get_api_handler(collection);
    mount.mount("/api/", api_handler);
    mount.mount("/", Static::new(Path::new("web")));

    Iron::new(mount).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Command line tool to exercise pulldown-cmark.

extern crate getopts;

extern crate pulldown_cmark;

use pulldown_cmark::Parser;
use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;

use std::env;
use std::io;
use std::io::{Read, Write};
use std::path::Path;
use std::fs::File;

fn render_html(text: &str, opts: Options) -> String {
    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new_ext(text, opts);
    html::push_html(&mut s, p);
    s
}

fn dry_run(text:&str, opts: Options) {
    let p = Parser::new_ext(text, opts);
    /*
    let events = p.collect::<Vec<_>>();
    let count = events.len();
    */
    let count = p.count();
    println!("{} events", count);
}

fn print_events(text: &str, opts: Options) {
    let mut p = Parser::new_ext(text, opts);
    loop {
        print!("{}: ", p.get_offset());
        if let Some(event) = p.next() {
            println!("{:?}", event);
        } else {
            break;
        }
    }
    println!("EOF");
}

fn read_file(filename: &str) -> String {
    let path = Path::new(filename);
    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), why),
        Ok(file) => file
    };
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), why),
        Ok(_) => s
    }
}

fn find_test_delim(text: &str) -> Option<usize> {
    if text.starts_with(".\n") { Some(0) }
    else { text.find("\n.\n").map(|pos| pos + 1) }
}

fn run_spec(spec_text: &str, args: &[String], opts: Options) {
    //println!("spec length={}, args={:?}", spec_text.len(), args);
    let (first, last) = if args.is_empty() {
        (None, None)
    } else {
        let mut iter = args[0].split("..");
        let first = iter.next().and_then(|s| s.parse().ok());
        let last = match iter.next() {
            Some(s) => s.parse().ok(),
            None => first
        };
        (first, last)
    };

    let mut test_number = 1;
    let mut tests_failed = 0;
    let mut tests_run = 0;
    let mut line_count = 0;
    let mut tail = spec_text;
    loop {
        let rest = match find_test_delim(tail) {
            Some(pos) => &tail[pos + 2 ..],
            None => break
        };
        let (source, rest) = match find_test_delim(rest) {
            Some(pos) => (&rest[..pos], &rest[pos + 2 ..]),
            None => break
        };
        let (html, rest) = match find_test_delim(rest) {
            Some(pos) => (&rest[.. pos], &rest[pos + 2 ..]),
            None => break
        };
        if first.map_or(true, |fst| fst <= test_number) &&
                last.map_or(true, |lst| test_number <= lst) {
            if tests_run == 0 || line_count == 0 || (test_number % 10 == 0) {
                if line_count > 30 {
                    println!("");
                    line_count = 0;
                } else if line_count > 0 {
                    print!(" ");
                }
                print!("[{}]", test_number);
            } else if line_count > 0 && (test_number % 10) == 5 {
                print!(" ");
            }
            let our_html = render_html(&source.replace("→", "\t").replace("\n", "\r\n"), opts);
            if our_html == html {
                print!(".");
            } else {
                if tests_failed == 0 {
                    print!("FAIL {}:\n---input---\n{}\n---wanted---\n{}\n---got---\n{}",
                        test_number, source, html, our_html);
                } else {
                    print!("X");
                }
                tests_failed += 1;
            }
            let _ = io::stdout().flush();
            tests_run += 1;
            line_count += 1;
        }
        tail = rest;
        test_number += 1;
    }
    println!("\n{}/{} tests passed", tests_run - tests_failed, tests_run)
}

pub fn main() {
    let args: Vec<_> = env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optflag("d", "dry-run", "dry run, produce no output");
    opts.optflag("e", "events", "print event sequence instead of rendering");
    opts.optflag("T", "enable-tables", "enable GitHub-style tables");
    opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes");
    opts.optopt("s", "spec", "run tests from spec file", "FILE");
    opts.optopt("b", "bench", "run benchmark", "FILE");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let mut opts = Options::empty();
    if matches.opt_present("enable-tables") {
        opts.insert(OPTION_ENABLE_TABLES);
    }
    if matches.opt_present("enable-footnotes") {
        opts.insert(OPTION_ENABLE_FOOTNOTES);
    }
    if let Some(filename) = matches.opt_str("spec") {
        run_spec(&read_file(&filename), &matches.free, opts);
    } else if let Some(filename) = matches.opt_str("bench") {
        let inp = read_file(&filename);
        for _ in 0..1000 {
            let _ = render_html(&inp, opts);
        }
    } else {
        let mut input = String::new();
        if let Err(why) = io::stdin().read_to_string(&mut input) {
            panic!("couldn't read from stdin: {}", why)
        }
        if matches.opt_present("events") {
            print_events(&input, opts);
        } else if matches.opt_present("dry-run") {
            dry_run(&input, opts);
        } else {
            print!("{}", render_html(&input, opts));
        }
    }
}
<commit_msg>update main.rs to parse the new test format in the spec<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Command line tool to exercise pulldown-cmark.

extern crate getopts;

extern crate pulldown_cmark;

use pulldown_cmark::Parser;
use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;

use std::env;
use std::io;
use std::io::{Read, Write};
use std::path::Path;
use std::fs::File;

fn render_html(text: &str, opts: Options) -> String {
    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new_ext(text, opts);
    html::push_html(&mut s, p);
    s
}

fn dry_run(text:&str, opts: Options) {
    let p = Parser::new_ext(text, opts);
    /*
    let events = p.collect::<Vec<_>>();
    let count = events.len();
    */
    let count = p.count();
    println!("{} events", count);
}

fn print_events(text: &str, opts: Options) {
    let mut p = Parser::new_ext(text, opts);
    loop {
        print!("{}: ", p.get_offset());
        if let Some(event) = p.next() {
            println!("{:?}", event);
        } else {
            break;
        }
    }
    println!("EOF");
}

fn read_file(filename: &str) -> String {
    let path = Path::new(filename);
    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), why),
        Ok(file) => file
    };
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), why),
        Ok(_) => s
    }
}

// Tests in the spec (v0.26) are of the form:
//
// ```````````````````````````````` example
// <markdown input>
// .
// <expected output>
// ````````````````````````````````
struct Spec<'a> {
    spec: &'a str,
    test_n: usize,
}

impl<'a> Spec<'a> {
    pub fn new(spec: &'a str) -> Self {
        Spec{ spec: spec, test_n: 0 }
    }
}

struct TestCase<'a> {
    n: usize,
    input: &'a str,
    expected: &'a str,
}

impl<'a> TestCase<'a> {
    pub fn new(n: usize, input: &'a str, expected: &'a str) -> Self {
        TestCase { n: n, input: input, expected: expected }
    }
}

impl<'a> Iterator for Spec<'a> {
    type Item = TestCase<'a>;

    fn next(&mut self) -> Option<TestCase<'a>> {
        let spec = self.spec;

        let i_start = match self.spec.find("```````````````````````````````` example\n").map(|pos| pos + 41) {
            Some(pos) => pos,
            None => return None,
        };

        let i_end = match self.spec[i_start..].find("\n.\n").map(|pos| pos + i_start){
            Some(pos) => pos,
            None => return None,
        };

        let e_end = match self.spec[i_end + 3..].find("````````````````````````````````\n").map(|pos| pos + i_end + 3){
            Some(pos) => pos,
            None => return None,
        };

        self.test_n += 1;
        self.spec = &self.spec[e_end + 33 ..];

        Some(TestCase::new(self.test_n, &spec[i_start .. i_end], &spec[i_end + 3 .. e_end]))
    }
}

fn run_spec(spec_text: &str, args: &[String], opts: Options) {
    //println!("spec length={}, args={:?}", spec_text.len(), args);
    let (first, last) = if args.is_empty() {
        (None, None)
    } else {
        let mut iter = args[0].split("..");
        let first = iter.next().and_then(|s| s.parse().ok());
        let last = match iter.next() {
            Some(s) => s.parse().ok(),
            None => first
        };
        (first, last)
    };

    let spec = Spec::new(spec_text);
    let mut tests_failed = 0;
    let mut tests_run = 0;
    let mut line_count = 0;

    for test in spec {
        if first.map(|fst| test.n < fst).unwrap_or(false) { continue }
        if last.map(|lst| test.n > lst).unwrap_or(false) { break }

        if tests_run == 0 || line_count == 0 || (test.n % 10 == 0) {
            if line_count > 30 {
                println!("");
                line_count = 0;
            } else if line_count > 0 {
                print!(" ");
            }
            print!("[{:3}]", test.n);
        } else if line_count > 0 && (test.n % 10) == 5 {
            print!(" ");
        }

        let our_html = render_html(&test.input.replace("→", "\t").replace("\n", "\r\n"), opts);

        if our_html == test.expected {
            print!(".");
        } else {
            if tests_failed == 0 {
                print!("FAIL {}:\n\n---input---\n{}\n\n---wanted---\n{}\n\n---got---\n{}\n",
                    test.n, test.input, test.expected, our_html);
            } else {
                print!("X");
            }
            tests_failed += 1;
        }

        let _ = io::stdout().flush();
        tests_run += 1;
        line_count += 1;
    }

    println!("\n{}/{} tests passed", tests_run - tests_failed, tests_run)
}

pub fn main() {
    let args: Vec<_> = env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optflag("d", "dry-run", "dry run, produce no output");
    opts.optflag("e", "events", "print event sequence instead of rendering");
    opts.optflag("T", "enable-tables", "enable GitHub-style tables");
    opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes");
    opts.optopt("s", "spec", "run tests from spec file", "FILE");
    opts.optopt("b", "bench", "run benchmark", "FILE");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let mut opts = Options::empty();
    if matches.opt_present("enable-tables") {
        opts.insert(OPTION_ENABLE_TABLES);
    }
    if matches.opt_present("enable-footnotes") {
        opts.insert(OPTION_ENABLE_FOOTNOTES);
    }
    if let Some(filename) = matches.opt_str("spec") {
        run_spec(&read_file(&filename), &matches.free, opts);
    } else if let Some(filename) = matches.opt_str("bench") {
        let inp = read_file(&filename);
        for _ in 0..1000 {
            let _ = render_html(&inp, opts);
        }
    } else {
        let mut input = String::new();
        if let Err(why) = io::stdin().read_to_string(&mut input) {
            panic!("couldn't read from stdin: {}", why)
        }
        if matches.opt_present("events") {
            print_events(&input, opts);
        } else if matches.opt_present("dry-run") {
            dry_run(&input, opts);
        } else {
            print!("{}", render_html(&input, opts));
        }
    }
}
<|endoftext|>


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

use clap::{Arg, App};

fn main() {
    App::new("Helium")
        .version(crate_version!())
        .author(crate_authors!())
        .about("The awesomest of editors.")
        .arg(Arg::with_name("file")
            .help("Input file")
            .index(1))
        .get_matches();

    let sdl_context = sdl2::init().unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();
    let window = sdl_context.video()
        .unwrap()
        .window("Helium", 800, 600)
        .resizable()
        .allow_highdpi()
        .build()
        .unwrap();
    let mut renderer = window.renderer()
        .accelerated()
        .present_vsync()
        .build()
        .unwrap();
    let font = ttf_context.load_font(std::path::Path::new("DejaVuSansMono.ttf"), 24).unwrap();
    let hello =
        font.render("Hello world!").blended(sdl2::pixels::Color::RGB(150, 150, 150)).unwrap();
    let rect = sdl2::rect::Rect::new(0, 0, hello.width(), hello.height());
    let mut hello_texture = renderer.create_texture_from_surface(&hello).unwrap();
    renderer.set_draw_color(sdl2::pixels::Color::RGB(30, 35, 40));

    for event in sdl_context.event_pump().unwrap().wait_iter() {
        match event {
            sdl2::event::Event::Quit { .. } => return,
            sdl2::event::Event::Window { .. } => {
                renderer.clear();
                renderer.copy(&mut hello_texture, None, Some(rect)).unwrap();
                renderer.present();
            }
            _ => {}
        }
    }
}
<commit_msg>Added unicode test character.<commit_after>extern crate sdl2;
#[macro_use]
extern crate clap;

use clap::{Arg, App};

fn main() {
    App::new("Helium")
        .version(crate_version!())
        .author(crate_authors!())
        .about("The awesomest of editors.")
        .arg(Arg::with_name("file")
            .help("Input file")
            .index(1))
        .get_matches();

    let sdl_context = sdl2::init().unwrap();
    let ttf_context = sdl2::ttf::init().unwrap();
    let window = sdl_context.video()
        .unwrap()
        .window("Helium", 800, 600)
        .resizable()
        .allow_highdpi()
        .build()
        .unwrap();
    let mut renderer = window.renderer()
        .accelerated()
        .present_vsync()
        .build()
        .unwrap();
    let font = ttf_context.load_font(std::path::Path::new("DejaVuSansMono.ttf"), 24).unwrap();
    let hello =
        font.render("Hello world!☺").blended(sdl2::pixels::Color::RGB(150, 150, 150)).unwrap();
    let rect = sdl2::rect::Rect::new(0, 0, hello.width(), hello.height());
    let mut hello_texture = renderer.create_texture_from_surface(&hello).unwrap();
    renderer.set_draw_color(sdl2::pixels::Color::RGB(30, 35, 40));

    for event in sdl_context.event_pump().unwrap().wait_iter() {
        match event {
            sdl2::event::Event::Quit { .. } => return,
            sdl2::event::Event::Window { .. } => {
                renderer.clear();
                renderer.copy(&mut hello_texture, None, Some(rect)).unwrap();
                renderer.present();
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();
  let mut search = args.initial_search.clone();
  if args.use_first {
    let matches = matching::compute_matches(&choices, search.as_slice());
    println!("{}", matches[0]);
    return;
  }

  let mut screen = Screen::open_screen();
  let mut index = 0;

  let visible_choices = min(20, screen.height - 1);

  let start_line = screen.height - visible_choices - 1;
  loop {
    screen.hide_cursor();
    screen.blank_screen(start_line);
    screen.move_cursor(start_line, 0);
    let matches = matching::compute_matches(&choices, search.as_slice());
    let mut i = 1;
    screen.write(format!("> {} ({} choices)\n", search.as_slice(), choices.len()).as_slice());
    for choice in matches.iter() {
      if i == index + 1 {
        screen.write_inverted(choice.as_slice());
      } else {
        screen.write(choice.as_slice());
      }
      if i >= visible_choices as usize {
        break;
      } else {
        screen.write("\n");
      }
      i += 1;
    }

    screen.move_cursor(start_line, 2 + search.len() as u16);
    screen.show_cursor();

    match screen.tty.getchar() {
      Char(x) => {
        search.push(x);
        index = 0;
      }
      Backspace => { search.pop(); }
      Control('h') => { search.pop(); }
      Control('u') => { search.clear(); }
      Control('c') => { return; }
      Control('n') => { index = min(index + 1, min(visible_choices as usize - 1, matches.len() - 1)); }
      Control('p') => { index = if index == 0 { 0 } else { index - 1 }; }
      Enter => {
        screen.move_cursor(start_line + visible_choices, 0);
        screen.write("\n");
        println!("{}", matches[index]);
        break;
      }
      _ => panic!("Unexpected input"),
    }
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  loop {
    match stdin.read_line() {
      Ok(x) => lines.push(String::from_str(x.as_slice().trim())),
      Err(_) => break,
    }
  }

  lines
}
<commit_msg>Avoid unnecessary copying of stdin lines<commit_after>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();
  let mut search = args.initial_search.clone();
  if args.use_first {
    let matches = matching::compute_matches(&choices, search.as_slice());
    println!("{}", matches[0]);
    return;
  }

  let mut screen = Screen::open_screen();
  let mut index = 0;

  let visible_choices = min(20, screen.height - 1);

  let start_line = screen.height - visible_choices - 1;
  loop {
    screen.hide_cursor();
    screen.blank_screen(start_line);
    screen.move_cursor(start_line, 0);
    let matches = matching::compute_matches(&choices, search.as_slice());
    let mut i = 1;
    screen.write(format!("> {} ({} choices)\n", search.as_slice(), choices.len()).as_slice());
    for choice in matches.iter() {
      if i == index + 1 {
        screen.write_inverted(choice.as_slice());
      } else {
        screen.write(choice.as_slice());
      }
      if i >= visible_choices as usize {
        break;
      } else {
        screen.write("\n");
      }
      i += 1;
    }

    screen.move_cursor(start_line, 2 + search.len() as u16);
    screen.show_cursor();

    match screen.tty.getchar() {
      Char(x) => {
        search.push(x);
        index = 0;
      }
      Backspace => { search.pop(); }
      Control('h') => { search.pop(); }
      Control('u') => { search.clear(); }
      Control('c') => { return; }
      Control('n') => { index = min(index + 1, min(visible_choices as usize - 1, matches.len() - 1)); }
      Control('p') => { index = if index == 0 { 0 } else { index - 1 }; }
      Enter => {
        screen.move_cursor(start_line + visible_choices, 0);
        screen.write("\n");
        println!("{}", matches[index]);
        break;
      }
      _ => panic!("Unexpected input"),
    }
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  while let Ok(mut s) = stdin.read_line() {
    trim(&mut s);
    lines.push(s);
  }

  lines
}

fn trim(s: &mut String) {
  while let Some(x) = s.pop() {
    if x != '\n' {
      s.push(x);
      return;
    }
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;

#[derive(Debug, PartialEq)]
enum Atom {
    Number(f64),
    Symbol(String)
}

enum ParseAtomError {
    IncorrectSymbolName
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Number(n) => {
                write!(f, "{}", n)
            },
            Atom::Symbol(ref name) => {
                write!(f, "'{}", name)
            }
        }
    }
}

impl FromStr for Atom {
    type Err = ParseAtomError;

    fn from_str(s: &str) -> Result<Atom, ParseAtomError> {
        match s.parse::<f64>() {
            Ok(f) => {
                Ok(Atom::Number(f))
            },
            Err(..) => {
                match s.chars().next() {
                    Some(c) => {
                        if c.is_numeric() {
                            Err(ParseAtomError::IncorrectSymbolName)
                        } else {
                            Ok(Atom::Symbol(s.to_string()))
                        }
                    },
                    None => {
                        Err(ParseAtomError::IncorrectSymbolName)
                    }
                }
            }
        }
    }
}

fn tokenize(s: &str) -> Vec<String> {
    s.replace("("," ( ")
        .replace(")", " ) ")
        .replace("\n", " ")
        .split(' ')
        .filter_map(|s| { if s.is_empty() { None } else { Some(s.to_string()) }})
        .collect()
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
}

#[cfg(test)]
mod test {
    use super::{Atom, tokenize};

    #[test]
    fn parse_integer() {
        assert_eq!(Atom::Number(64f64), "64".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn parse_float() {
        assert_eq!(Atom::Number(64.5), "64.5".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn parse_symbol() {
        assert_eq!(Atom::Symbol("name".to_string()), "name".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn tokenize_dense_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize("(def a 1)"))
    }

    #[test]
    fn tokenize_sparse_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize(" ( \n def a\n1)   \n"))
    }
}
<commit_msg>Simplify matching in from_str impl for Atom<commit_after>use std::fmt;
use std::str::FromStr;

#[derive(Debug, PartialEq)]
enum Atom {
    Number(f64),
    Symbol(String)
}

enum ParseAtomError {
    IncorrectSymbolName
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Number(n) => {
                write!(f, "{}", n)
            },
            Atom::Symbol(ref name) => {
                write!(f, "'{}", name)
            }
        }
    }
}

impl FromStr for Atom {
    type Err = ParseAtomError;

    fn from_str(s: &str) -> Result<Atom, ParseAtomError> {
        match s.parse::<f64>() {
            Ok(f) => {
                Ok(Atom::Number(f))
            },
            Err(..) => {
                match s.chars().next() {
                    Some(c) if !c.is_numeric() => {
                        Ok(Atom::Symbol(s.to_string()))
                    },
                    _ => {
                        Err(ParseAtomError::IncorrectSymbolName)
                    }
                }
            }
        }
    }
}

fn tokenize(s: &str) -> Vec<String> {
    s.replace("("," ( ")
        .replace(")", " ) ")
        .replace("\n", " ")
        .split(' ')
        .filter_map(|s| { if s.is_empty() { None } else { Some(s.to_string()) }})
        .collect()
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
}

#[cfg(test)]
mod test {
    use super::{Atom, tokenize};

    #[test]
    fn parse_integer() {
        assert_eq!(Atom::Number(64f64), "64".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn parse_float() {
        assert_eq!(Atom::Number(64.5), "64.5".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn parse_symbol() {
        assert_eq!(Atom::Symbol("name".to_string()), "name".parse::<Atom>().ok().unwrap())
    }

    #[test]
    fn tokenize_dense_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize("(def a 1)"))
    }

    #[test]
    fn tokenize_sparse_expression() {
        let expected_result = ["(", "def", "a", "1", ")"]
                                .iter()
                                .map(|s| { s.to_string() })
                                .collect();
        assert_eq!(expected_result, tokenize(" ( \n def a\n1)   \n"))
    }
}
<|endoftext|>


<commit_before>mod vm;
mod command;
mod parse;
mod program;

use std::io::{Write, Read};
use std::env;
use std::path::Path;
use std::fs::File;

use vm::VM;
use program::Program;
use parse::parse;

fn main() {
    let vm = VM::new();
    let program = Program::new();
    match env::args().nth(1) {
        None => repl(vm, program),
        Some(arg) => interpreter(arg, vm, program),
    }
}

fn repl (mut vm: VM, mut program: Program) -> () {
    loop {
        print!("{}", if program.is_seeking {"... "} else {"tf> "});
        std::io::stdout().flush().unwrap();

        let mut line = String::new();
        let commands = match std::io::stdin().read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => parse(&line),
            Err(error) => panic!(error),
        };
        program.append(&commands);
        program.execute(&mut vm);
    }
}

fn interpreter(arg: String, mut vm: VM, mut program: Program) -> () {
    let path = Path::new(&arg);
    let mut contents = String::new();
    File::open(&path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    program.append(&parse(&contents));
    program.execute(&mut vm);
}
<commit_msg>Change main to provide instance to VM instance<commit_after>mod vm;
mod command;
mod parse;
mod program;

use std::io::{stdout, Write, Read};
use std::env;
use std::path::Path;
use std::fs::File;

use vm::VM;
use program::Program;
use parse::parse;

fn main() {
    let vm = VM::new(Some(stdout()));
    let program = Program::new();
    match env::args().nth(1) {
        None => repl(vm, program),
        Some(arg) => interpreter(arg, vm, program),
    }
}

fn repl (mut vm: VM, mut program: Program) -> () {
    loop {
        print!("{}", if program.is_seeking {"... "} else {"tf> "});
        std::io::stdout().flush().unwrap();

        let mut line = String::new();
        let commands = match std::io::stdin().read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => parse(&line),
            Err(error) => panic!(error),
        };
        program.append(&commands);
        program.execute(&mut vm);
    }
}

fn interpreter(arg: String, mut vm: VM, mut program: Program) -> () {
    let path = Path::new(&arg);
    let mut contents = String::new();
    File::open(&path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    program.append(&parse(&contents));
    program.execute(&mut vm);
}
<|endoftext|>


<commit_before>#![feature(io, slice_patterns)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while match chars.peek() {
                    Some(&Ok(c)) if c != ']' => true,
                    _ => false
                } {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<commit_msg>test: op-stream optimizer tests<commit_after>#![feature(io, slice_patterns)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while match chars.peek() {
                    Some(&Ok(c)) if c != ']' => true,
                    _ => false
                } {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    macro_rules! assert_let(
        ($test:pat, $value:expr, $then:block) => (
            if let $test = $value {
                $then
            } else {
                panic!("{:?} doesn't match {}", $value, stringify!($test))
            }
        );
        ($test:pat, $value:expr) => (
            assert_let!($test, $value, {})
        );
    );

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }

    #[test]
    fn opstream_new_empty() {
        let opstream = OpStream::new();
        assert_eq!(0, opstream.ops.len());
    }

    #[test]
    fn opstream_optimize() {
        let mut opstream = OpStream::new();
        opstream.add(Mov(1));
        opstream.add(Mov(1));
        opstream.add(Add(1));
        opstream.add(Add(-1));
        opstream.add(Add(-1));
        opstream.add(Mov(1));
        opstream.add(Mov(-1));
        let mut opstream2 = OpStream::new();
        opstream2.add(Mov(2));
        opstream2.add(Mov(3));
        opstream.add(Loop(opstream2));
        opstream.optimize();

        assert_let!([Mov(2), Add(-1), Loop(ref s2)], &opstream.ops[..], {
            assert_let!([Mov(5)], &s2.ops[..]);
        });
    }
}
<|endoftext|>


<commit_before>extern crate time;

fn main() {
    let dow = ["Duinday", "Sitaday", "Wikiday", "Tuxday", "Gnuday", "Commonday"];
    let moy = ["Jabim", "Zodrak", "Trogool", "Yanar", "Shkumbe", "Habniah", "Skarl", "Mikon", "Pertunda", "Kib", "Broket"];
    let dpm = 33;
    let dpw = dow.len();
    let mpy = moy.len();
    let (year, month, day, yoff) = current_day(time::now());
    let wd = (yoff + month * 3 + day) % dpw;
    let mut moff = yoff;

    for mm in 0..mpy {
        let spaces = (17 - moy[mm].len()) / 2;
        for _ in 0..spaces {
            print!(" ");
        }
        println!("{}", moy[mm]);

        for dd in 0..dpw {
            let mut abbrd = String::from(dow[dd]);
            abbrd.truncate(2);
            print!("{} ", abbrd);
        }

        let dd = if mm == month { day } else { 1000 };
        moff = print_days(moff, dpm, dpw, dd);
        if mm == 2 {
            println!("--  Peer  Day  --");
        }
        else if mm == 6 {
            println!("--Torrent Feast--");
        }
        else if is_leap_year(year) && mm == 10 {
            println!("--Immersion Day--");
        }
    }

    let mut datestr = format!("{}, {:02} of {}", dow[wd], day, moy[month]);
    let mut daystr = format!("{:02}.{:02}", month + 1, day);
    if day == 34 {
        if month == 2 {
            datestr = format!("Peer Day");
            daystr = format!("P");
        }
        else if month == 6 {
            datestr = format!("Torrent Feast");
            daystr = format!("T");
        }
        else if month == 10 {
            datestr = format!("Immersion Feast");
            daystr = format!("T");
        }
    }
    let hol = format!("{}", what_holiday(month, day));
    println!("Today is {} {}{}.  [{}.{}]", datestr, year, hol, year, daystr);
}

fn print_days(moff: usize, dpm: usize, dpw: usize, highlight: usize) -> usize {
    if moff != 0 {
        println!("");
    }

    for _ in 0 .. moff {
        print!("   ");
    }

    for day in 1 .. dpm + 1 {
        if (day + moff) % dpw == 1 {
            println!("");
        }

        let ch = if day == highlight { ">" } else if day + 1 == highlight { "<" } else { " " };
        print!("{:2}{}", day, ch);
    }

    println!("");
    return if moff == 0 { 3 } else { 0 };
}

fn current_day(current_time: time::Tm) -> (usize, usize, usize, usize) {
    let epoch_days_offset = 1483889;
    let seconds_per_day = 86400;
    let now = current_time.to_timespec();
    let days_since_epoch = (epoch_days_offset + now.sec / seconds_per_day) as i32;
    let days_per_year = 365;
    let leap_year = 4;
    let not_leap_year = 33;
    let days_per_month = 33;

    let mut count = 1;
    let mut days_remaining = days_since_epoch;
    let mut year = 0;
    while days_remaining > days_per_year + 1 {
        days_remaining -= days_per_year;
        year += 1;
        if count > not_leap_year {
            count = 1;
        }
        if count % leap_year == 0 {
            days_remaining -= 1;
        }
        count += 1;
    }
    if days_remaining == days_per_year + 1 && count % leap_year == 0 {
        days_remaining = 0;
        year += 1;
    }

    let mut month = 0;
    while days_remaining > days_per_month {
        month += 1;
        days_remaining -= days_per_month;
        if month == 3 || month == 7 || month == 11 {
            days_remaining -= 1;
        }
    }

    let day = days_remaining;
    return (year, month as usize, day as usize + 1, (year % 2 * 3) as usize);
}

fn is_leap_year(year: usize) -> bool {
    let rem = year % 33;
    return rem != 0 && rem % 4 == 0;
}

fn what_holiday(month: usize, day: usize) -> String {
    let mut result = format!("");
    if month == 0 && day == 1 {
        result = format!(", New Year's Day");
    }
    else if month == 2 && day == 12 {
        result = format!(", Purification Day");
    }
    else if month == 5 && day == 4 {
        result = format!(", Harvest Gift");
    }
    else if month == 7 && day == 29 {
        result = format!(", Familytide");
    }
    else if month == 10 && day == 21 {
        result = format!(", Freedom Day");
    }
    else if month == 0 && day == 27 {
        result = format!(", International Workers' Day");
    }
    return result;
}

<commit_msg>Add various Free Culture days - may need to be adjusted<commit_after>extern crate time;

fn main() {
    let dow = ["Duinday", "Sitaday", "Wikiday", "Tuxday", "Gnuday", "Commonday"];
    let moy = ["Jabim", "Zodrak", "Trogool", "Yanar", "Shkumbe", "Habniah", "Skarl", "Mikon", "Pertunda", "Kib", "Broket"];
    let dpm = 33;
    let dpw = dow.len();
    let mpy = moy.len();
    let (year, month, day, yoff) = current_day(time::now());
    let wd = (yoff + month * 3 + day) % dpw;
    let mut moff = yoff;

    for mm in 0..mpy {
        let spaces = (17 - moy[mm].len()) / 2;
        for _ in 0..spaces {
            print!(" ");
        }
        println!("{}", moy[mm]);

        for dd in 0..dpw {
            let mut abbrd = String::from(dow[dd]);
            abbrd.truncate(2);
            print!("{} ", abbrd);
        }

        let dd = if mm == month { day } else { 1000 };
        moff = print_days(moff, dpm, dpw, dd);
        if mm == 2 {
            println!("--  Peer  Day  --");
        }
        else if mm == 6 {
            println!("--Torrent Feast--");
        }
        else if is_leap_year(year) && mm == 10 {
            println!("--Immersion Day--");
        }
    }

    let mut datestr = format!("{}, {:02} of {}", dow[wd], day, moy[month]);
    let mut daystr = format!("{:02}.{:02}", month + 1, day);
    if day == 34 {
        if month == 2 {
            datestr = format!("Peer Day");
            daystr = format!("P");
        }
        else if month == 6 {
            datestr = format!("Torrent Feast");
            daystr = format!("T");
        }
        else if month == 10 {
            datestr = format!("Immersion Feast");
            daystr = format!("T");
        }
    }
    let hol = format!("{}", what_holiday(month, day));
    println!("Today is {} {}{}.  [{}.{}]", datestr, year, hol, year, daystr);
}

fn print_days(moff: usize, dpm: usize, dpw: usize, highlight: usize) -> usize {
    if moff != 0 {
        println!("");
    }

    for _ in 0 .. moff {
        print!("   ");
    }

    for day in 1 .. dpm + 1 {
        if (day + moff) % dpw == 1 {
            println!("");
        }

        let ch = if day == highlight { ">" } else if day + 1 == highlight { "<" } else { " " };
        print!("{:2}{}", day, ch);
    }

    println!("");
    return if moff == 0 { 3 } else { 0 };
}

fn current_day(current_time: time::Tm) -> (usize, usize, usize, usize) {
    let epoch_days_offset = 1483889;
    let seconds_per_day = 86400;
    let now = current_time.to_timespec();
    let days_since_epoch = (epoch_days_offset + now.sec / seconds_per_day) as i32;
    let days_per_year = 365;
    let leap_year = 4;
    let not_leap_year = 33;
    let days_per_month = 33;

    let mut count = 1;
    let mut days_remaining = days_since_epoch;
    let mut year = 0;
    while days_remaining > days_per_year + 1 {
        days_remaining -= days_per_year;
        year += 1;
        if count > not_leap_year {
            count = 1;
        }
        if count % leap_year == 0 {
            days_remaining -= 1;
        }
        count += 1;
    }
    if days_remaining == days_per_year + 1 && count % leap_year == 0 {
        days_remaining = 0;
        year += 1;
    }

    let mut month = 0;
    while days_remaining > days_per_month {
        month += 1;
        days_remaining -= days_per_month;
        if month == 3 || month == 7 || month == 11 {
            days_remaining -= 1;
        }
    }

    let day = days_remaining;
    return (year, month as usize, day as usize + 1, (year % 2 * 3) as usize);
}

fn is_leap_year(year: usize) -> bool {
    let rem = year % 33;
    return rem != 0 && rem % 4 == 0;
}

fn what_holiday(month: usize, day: usize) -> String {
    let mut result = format!("");
    if month == 0 && day == 1 {
        result = format!(", New Year's Day");
    }
    else if month == 2 && day == 12 {
        result = format!(", Purification Day");
    }
    else if month == 2 && day == 24 {
        result = format!(", Document Freedom Day");
    }
    else if month == 3 && day == 33 {
        result = format!(", Hardware Freedom Day");
    }
    else if month == 5 && day == 4 {
        result = format!(", Harvest Gift");
    }
    else if month == 5 && day == 9 {
        result = format!(", Culture Freedom Day");
    }
    else if month == 7 && day == 29 {
        result = format!(", Familytide");
    }
    else if month == 8 && day == 33 {
        result = format!(", Software Freedom Day");
    }
    else if month == 9 && day == 30 {
        result = format!(", Open Access Day");
    }
    else if month == 10 && day == 21 {
        result = format!(", Freedom Day");
    }
    else if month == 0 && day == 27 {
        result = format!(", International Workers' Day");
    }
    return result;
}

<|endoftext|>


<commit_before>use std::collections::LinkedList;

struct Operator {
    operators: LinkedList<Operator>,
    operands: LinkedList<Operand>,
    runner: Box<Fn(&Operand) -> Operand>
}

impl Operator {
    fn new(runner: Box<Fn(&Operand) -> Operand>) -> Operator {
        Operator { operators: LinkedList::new(),
                   operands: LinkedList::new(),
                   runner: runner }
    }
    fn feed(&mut self, operand: Operand) {
        self.operands.push_back(operand);
    }
    fn run<F: Fn(&Operand) -> Operand>(&mut self) {
        let mut iter = self.operands.iter();
        loop {
               match iter.next() {
                   Some(x) => { },
                   None => { break; }
            }
        }
    }
}

enum Operand {
    Number(f64),
    Symbol(String),
    Operator(Operator),
    Sentinel
}

fn main() {
    let mut a = LinkedList::new();
    let mut b = LinkedList::new();
    a.push_back(1);
    a.push_back(2);
    b.push_back(3);
    b.push_back(4);

    a.append(&mut b);

    for e in &a {
        println!("{}", e); // prints 1, then 2, then 3, then 4
    }
    println!("{}", b.len()); // prints 0

    let mut op: Operator = Operator::new(Box::new(|x: &Operand| -> Operand {
        match *x {
            Operand::Number(y) => {
                println!("{:?}", y);
            },
            _ => { println!("fail!"); }
        }
        Operand::Sentinel
    }));
    op.feed(Operand::Number(777f64));
    op.feed(Operand::Symbol(String::from("hello")));

    // op.run(|x: &Operand| -> Operand {
    //     match *x {
    //         Operand::Number(y) => {
    //             println!("{:?}", y);
    //         },
    //         _ => { println!("fail!"); }
    //     }
    //     Operand::Sentinel
    // });
}<commit_msg>Making runner work.<commit_after>use std::collections::LinkedList;

struct Operator {
    operators: LinkedList<Operator>,
    operands: LinkedList<Operand>,
    runner: Box<Fn(&Operand) -> Operand>
}

impl Operator {
    fn new(runner: Box<Fn(&Operand) -> Operand>) -> Operator {
        Operator { operators: LinkedList::new(),
                   operands: LinkedList::new(),
                   runner: runner }
    }
    fn feed(&mut self, operand: Operand) {
        self.operands.push_back(operand);
    }
    fn run(&mut self) {
        let mut iter = self.operands.iter();
        let ref runner = self.runner;
        loop {
               match iter.next() {
                   Some(x) => { runner(x); },
                   None => { break; }
            }
        }
    }
}

enum Operand {
    Number(f64),
    Symbol(String),
    Operator(Operator),
    Sentinel
}

fn main() {
    let mut a = LinkedList::new();
    let mut b = LinkedList::new();
    a.push_back(1);
    a.push_back(2);
    b.push_back(3);
    b.push_back(4);

    a.append(&mut b);

    for e in &a {
        println!("{}", e); // prints 1, then 2, then 3, then 4
    }
    println!("{}", b.len()); // prints 0

    let mut op: Operator = Operator::new(Box::new(|x: &Operand| -> Operand {
        match *x {
            Operand::Number(y) => {
                println!("{:?}", y);
            },
            _ => { println!("fail!"); }
        }
        Operand::Sentinel
    }));
    op.feed(Operand::Number(777f64));
    op.feed(Operand::Symbol(String::from("hello")));

    op.run();
}
<|endoftext|>