<commit_before>extern crate hyper;
extern crate rustc_serialize;
extern crate chrono;
extern crate regex;
extern crate env_logger;
extern crate log;
extern crate docopt;

use std::ascii::AsciiExt;
use std::io::Read;
use std::env;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::fmt;
use std::error::Error;
use std::result;

use chrono::naive::datetime::NaiveDateTime;
use chrono::offset::local::Local;
use chrono::offset::fixed::FixedOffset;
use chrono::datetime::DateTime;
use chrono::Datelike;

use rustc_serialize::json;
use rustc_serialize::Decodable;
use hyper::client::Client;

use regex::Regex;

use docopt::Docopt;

static USAGE: &'static str = "
Washing State Ferry Schedules

Usage:
  wsf [options] <from> <to>
  wsf -h

  <from> and <to> are a prefix of the departing terminal and arriving
  terminal, respectively. For example 'wsf sea ba' is equivalent to
  'wsf Seattle \"Bainbridge Island\"'.

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

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_from: String,
    arg_to: String,
}

fn run() -> Result<()> {
    try!(env_logger::init());

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let from_in: &str = &args.arg_from.to_ascii_lowercase();
    let to_in: &str   = &args.arg_to.to_ascii_lowercase();

    // pull in api key at *build* time from environment
    let mut s = Session::new(env!("WSDOT_API_KEY"));

    let now = Local::now();
    let mut from: Option<i32> = None;
    let mut to: Option<i32> = None;
    for terminal in try!(s.terminals()).iter() {
        if terminal.Description.to_ascii_lowercase().starts_with(&from_in) {
            from = Some(terminal.TerminalID);
        }
        if terminal.Description.to_ascii_lowercase().starts_with(&to_in) {
            to = Some(terminal.TerminalID);
        }
    }
    let from = try!(from.ok_or(CliError::BadInput(format!("'{}' is not a known port!", from_in))));
    let to = try!(to.ok_or(CliError::BadInput(format!("'{}' is not a known port!", to_in))));
    let tc = try!(s.schedule(from, to));
    for time in tc.Times.iter() {
        if time.depart_time() > now {
            println!("{}\t{}\t{}\t{}",
                     time.depart_time().time(),
                     tc.DepartingTerminalName,
                     tc.ArrivingTerminalName,
                     time.VesselName );
        }
    }
    s.save_cache()
}

fn main() {
    match run() {
        Ok(_) => {},
        Err(e) => {
            // TODO print to STDERR instead of STDOUT
            println!("{}", e);
            std::process::exit(1);
        }
    }
}

struct Session {
    api_key: String,
    client: Client,
    cache: Cache,
    cacheflushdate: String,
    cache_path: String,
    offline: bool,
}

impl Session {

    fn new(api_key: &str) -> Session {
        let mut cache_path: PathBuf = env::home_dir().unwrap();
        cache_path.push(".wsf.cache");
        let cache_path = format!("{}", cache_path.display());

        let mut s = Session {
            api_key: api_key.to_string(),
            client: Client::new(),
            cache: Cache::load(&cache_path).unwrap_or(Cache::empty()),
            cacheflushdate: String::new(),
            cache_path: cache_path,
            offline: false,
        };

        // TODO this is kind of gross, cfd as optional to indicate offline, maybe?
        s.offline = match s.get::<String>("/cacheflushdate".to_owned()) {
            Ok(cfd) => {
                    s.cacheflushdate = cfd;
                    false
                },
            Err(_) => true,
        };
        return s;
    }

    fn save_cache(&mut self) -> Result<()> {
        self.cache.cache_flush_date = self.cacheflushdate.clone();

        let mut f = try!(File::create(&self.cache_path));
        let encoded = try!(json::encode(&self.cache));
        Ok(try!(f.write_all(encoded.as_bytes())))
    }

    fn get<T: Decodable>(&self, path: String) -> Result<T> {
        let url = &format!("http://www.wsdot.wa.gov/ferries/api/schedule/rest{}?apiaccesscode={}",
                            path,
                            self.api_key);
        let mut res = try!(self.client.get(url).send());
        assert_eq!(res.status, hyper::Ok);

        let mut buf = String::new();
        try!(res.read_to_string(&mut buf));
        Ok(try!(json::decode::<T>(&buf)))
    }

    fn terminals(&mut self) -> Result<Vec<Terminal>> {
        if self.offline || (self.cache.cache_flush_date == self.cacheflushdate) {
            return Ok(self.cache.terminals.clone())
        }
        else {
            let now = Local::today();
            let path = format!("/terminals/{}-{}-{}", now.year(), now.month(), now.day());
            let routes: Vec<Terminal> = try!(self.get(path));
            self.cache.terminals = routes.clone();
            return Ok(routes);
        }
    }

    fn schedule(&mut self, from: i32, to: i32) -> Result<TerminalCombo> {
        let mut cache_is_stale = true;
        let cache_key = format!("{} {}", from, to);

        if self.offline || (self.cache.cache_flush_date == self.cacheflushdate) {
            if self.cache.sailings.contains_key(&cache_key) {
                // cache is up to date and has route!
                return Ok(self.cache.sailings.get(&cache_key)
                                              .expect("checked for key in cache then not found")
                                              .clone());
            }
            else {
                // cache is up to date, but we don't have this route in it
                cache_is_stale = false;
            }
        }

        if cache_is_stale {
            self.cache.sailings.clear();
        }

        let now = Local::now();
        let path = format!("/schedule/{}-{}-{}/{}/{}",
                            now.year(), now.month(), now.day(), from, to);

        let schedule: Schedule = try!(self.get(path));

        self.cache.sailings.insert(cache_key, schedule.TerminalCombos[0].clone());
        Ok(schedule.TerminalCombos[0].clone())
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct Cache {
    terminals: Vec<Terminal>,
    sailings: HashMap<String, TerminalCombo>,
    cache_flush_date: String,
}

impl Cache {

    fn empty() -> Cache {
        Cache {
            terminals: vec![],
            sailings: HashMap::new(),
            cache_flush_date: String::new(),
        }
    }

    fn load(path: &String) -> Result<Cache> {
        let mut f = try!(File::open(path));
        let mut s = String::new();
        try!(f.read_to_string(&mut s));
        let cache: Cache = try!(json::decode(&s));
        Ok(cache)
    }
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Terminal {
    TerminalID: i32,
    Description: String,
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
struct SailingTime {
    DepartingTime: String,
    ArrivingTime: Option<String>,
    VesselName: String,
}

impl SailingTime {
    // parse date strings of form "/Date(1436318400000-0700)/"
    fn depart_time(&self) -> DateTime<Local> {
        let re = Regex::new(r"^/Date\((\d{10})000-(\d{2})(\d{2})\)/$").unwrap();
        let caps = re.captures(&self.DepartingTime).unwrap();

        let epoch: i64 = caps.at(1).unwrap().parse().unwrap();
        let tz_hours: i32 = caps.at(2).unwrap().parse().unwrap();
        let tz_minutes: i32 = caps.at(3).unwrap().parse().unwrap();

        let nd = NaiveDateTime::from_timestamp(epoch, 0);
        let tz = FixedOffset::west((tz_hours * 3600) + (tz_minutes * 60));
        let fotz: DateTime<FixedOffset> = DateTime::from_utc(nd, tz);
        fotz.with_timezone(&Local)
    }
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
struct TerminalCombo {
    Times: Vec<SailingTime>,
    DepartingTerminalName: String,
    ArrivingTerminalName: String,
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Debug)]
struct Schedule {
    TerminalCombos: Vec<TerminalCombo>,
}

type Result<T> = result::Result<T, CliError>;

#[derive(Debug)]
enum CliError {
    Log(log::SetLoggerError),
    Parse(rustc_serialize::json::DecoderError),
    SaveCache(rustc_serialize::json::EncoderError),
    Http(hyper::error::Error),
    Io(std::io::Error),
    BadInput(String),
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CliError::Log(ref err) => format!("Unable to configure logging: {}", err).fmt(f),
            CliError::Parse(ref err) => format!("Unable to parse WSDOT Data: {}", err).fmt(f),
            CliError::SaveCache(ref err) => format!("Unable to save cache: {}", err).fmt(f),
            CliError::Http(ref err) => format!("Unable to communicate with WSDOT: {}", err).fmt(f),
            CliError::Io(ref err) => format!("Unable to read data: {}", err).fmt(f),
            CliError::BadInput(ref desc) => format!("Unable to understand input: {}", desc).fmt(f),
        }
    }
}

impl Error for CliError {
    fn description(&self) -> &str {
        match *self {
            CliError::BadInput(ref err) => err,
            _ => self.description(),
        }
    }
}

impl From<rustc_serialize::json::EncoderError> for CliError {
    fn from(err: rustc_serialize::json::EncoderError) -> CliError {
        CliError::SaveCache(err)
    }
}

impl From<log::SetLoggerError> for CliError {
    fn from(err: log::SetLoggerError) -> CliError {
        CliError::Log(err)
    }
}
impl From<hyper::error::Error> for CliError {
    fn from(err: hyper::error::Error) -> CliError {
        CliError::Http(err)
    }
}

impl From<std::io::Error> for CliError {
    fn from(err: std::io::Error) -> CliError {
        CliError::Io(err)
    }
}

impl From<rustc_serialize::json::DecoderError> for CliError {
    fn from(err: rustc_serialize::json::DecoderError) -> CliError {
        CliError::Parse(err)
    }
}
<commit_msg>make it build for other people<commit_after>extern crate hyper;
extern crate rustc_serialize;
extern crate chrono;
extern crate regex;
extern crate env_logger;
extern crate log;
extern crate docopt;

use std::ascii::AsciiExt;
use std::io::Read;
use std::env;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::fmt;
use std::error::Error;
use std::result;

use chrono::naive::datetime::NaiveDateTime;
use chrono::offset::local::Local;
use chrono::offset::fixed::FixedOffset;
use chrono::datetime::DateTime;
use chrono::Datelike;

use rustc_serialize::json;
use rustc_serialize::Decodable;
use hyper::client::Client;

use regex::Regex;

use docopt::Docopt;

static USAGE: &'static str = "
Washing State Ferry Schedules

Usage:
  wsf [options] <from> <to>
  wsf -h

  <from> and <to> are a prefix of the departing terminal and arriving
  terminal, respectively. For example 'wsf sea ba' is equivalent to
  'wsf Seattle \"Bainbridge Island\"'.

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

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_from: String,
    arg_to: String,
}

fn run() -> Result<()> {
    try!(env_logger::init());

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let from_in: &str = &args.arg_from.to_ascii_lowercase();
    let to_in: &str   = &args.arg_to.to_ascii_lowercase();

    let mut s = Session::new("afddf683-37c5-4d1a-8486-f7004a16d86d");

    let now = Local::now();
    let mut from: Option<i32> = None;
    let mut to: Option<i32> = None;
    for terminal in try!(s.terminals()).iter() {
        if terminal.Description.to_ascii_lowercase().starts_with(&from_in) {
            from = Some(terminal.TerminalID);
        }
        if terminal.Description.to_ascii_lowercase().starts_with(&to_in) {
            to = Some(terminal.TerminalID);
        }
    }
    let from = try!(from.ok_or(CliError::BadInput(format!("'{}' is not a known port!", from_in))));
    let to = try!(to.ok_or(CliError::BadInput(format!("'{}' is not a known port!", to_in))));
    let tc = try!(s.schedule(from, to));
    for time in tc.Times.iter() {
        if time.depart_time() > now {
            println!("{}\t{}\t{}\t{}",
                     time.depart_time().time(),
                     tc.DepartingTerminalName,
                     tc.ArrivingTerminalName,
                     time.VesselName );
        }
    }
    s.save_cache()
}

fn main() {
    match run() {
        Ok(_) => {},
        Err(e) => {
            // TODO print to STDERR instead of STDOUT
            println!("{}", e);
            std::process::exit(1);
        }
    }
}

struct Session {
    api_key: String,
    client: Client,
    cache: Cache,
    cacheflushdate: String,
    cache_path: String,
    offline: bool,
}

impl Session {

    fn new(api_key: &str) -> Session {
        let mut cache_path: PathBuf = env::home_dir().unwrap();
        cache_path.push(".wsf.cache");
        let cache_path = format!("{}", cache_path.display());

        let mut s = Session {
            api_key: api_key.to_string(),
            client: Client::new(),
            cache: Cache::load(&cache_path).unwrap_or(Cache::empty()),
            cacheflushdate: String::new(),
            cache_path: cache_path,
            offline: false,
        };

        // TODO this is kind of gross, cfd as optional to indicate offline, maybe?
        s.offline = match s.get::<String>("/cacheflushdate".to_owned()) {
            Ok(cfd) => {
                    s.cacheflushdate = cfd;
                    false
                },
            Err(_) => true,
        };
        return s;
    }

    fn save_cache(&mut self) -> Result<()> {
        self.cache.cache_flush_date = self.cacheflushdate.clone();

        let mut f = try!(File::create(&self.cache_path));
        let encoded = try!(json::encode(&self.cache));
        Ok(try!(f.write_all(encoded.as_bytes())))
    }

    fn get<T: Decodable>(&self, path: String) -> Result<T> {
        let url = &format!("http://www.wsdot.wa.gov/ferries/api/schedule/rest{}?apiaccesscode={}",
                            path,
                            self.api_key);
        let mut res = try!(self.client.get(url).send());
        assert_eq!(res.status, hyper::Ok);

        let mut buf = String::new();
        try!(res.read_to_string(&mut buf));
        Ok(try!(json::decode::<T>(&buf)))
    }

    fn terminals(&mut self) -> Result<Vec<Terminal>> {
        if self.offline || (self.cache.cache_flush_date == self.cacheflushdate) {
            return Ok(self.cache.terminals.clone())
        }
        else {
            let now = Local::today();
            let path = format!("/terminals/{}-{}-{}", now.year(), now.month(), now.day());
            let routes: Vec<Terminal> = try!(self.get(path));
            self.cache.terminals = routes.clone();
            return Ok(routes);
        }
    }

    fn schedule(&mut self, from: i32, to: i32) -> Result<TerminalCombo> {
        let mut cache_is_stale = true;
        let cache_key = format!("{} {}", from, to);

        if self.offline || (self.cache.cache_flush_date == self.cacheflushdate) {
            if self.cache.sailings.contains_key(&cache_key) {
                // cache is up to date and has route!
                return Ok(self.cache.sailings.get(&cache_key)
                                              .expect("checked for key in cache then not found")
                                              .clone());
            }
            else {
                // cache is up to date, but we don't have this route in it
                cache_is_stale = false;
            }
        }

        if cache_is_stale {
            self.cache.sailings.clear();
        }

        let now = Local::now();
        let path = format!("/schedule/{}-{}-{}/{}/{}",
                            now.year(), now.month(), now.day(), from, to);

        let schedule: Schedule = try!(self.get(path));

        self.cache.sailings.insert(cache_key, schedule.TerminalCombos[0].clone());
        Ok(schedule.TerminalCombos[0].clone())
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct Cache {
    terminals: Vec<Terminal>,
    sailings: HashMap<String, TerminalCombo>,
    cache_flush_date: String,
}

impl Cache {

    fn empty() -> Cache {
        Cache {
            terminals: vec![],
            sailings: HashMap::new(),
            cache_flush_date: String::new(),
        }
    }

    fn load(path: &String) -> Result<Cache> {
        let mut f = try!(File::open(path));
        let mut s = String::new();
        try!(f.read_to_string(&mut s));
        let cache: Cache = try!(json::decode(&s));
        Ok(cache)
    }
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Terminal {
    TerminalID: i32,
    Description: String,
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
struct SailingTime {
    DepartingTime: String,
    ArrivingTime: Option<String>,
    VesselName: String,
}

impl SailingTime {
    // parse date strings of form "/Date(1436318400000-0700)/"
    fn depart_time(&self) -> DateTime<Local> {
        let re = Regex::new(r"^/Date\((\d{10})000-(\d{2})(\d{2})\)/$").unwrap();
        let caps = re.captures(&self.DepartingTime).unwrap();

        let epoch: i64 = caps.at(1).unwrap().parse().unwrap();
        let tz_hours: i32 = caps.at(2).unwrap().parse().unwrap();
        let tz_minutes: i32 = caps.at(3).unwrap().parse().unwrap();

        let nd = NaiveDateTime::from_timestamp(epoch, 0);
        let tz = FixedOffset::west((tz_hours * 3600) + (tz_minutes * 60));
        let fotz: DateTime<FixedOffset> = DateTime::from_utc(nd, tz);
        fotz.with_timezone(&Local)
    }
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
struct TerminalCombo {
    Times: Vec<SailingTime>,
    DepartingTerminalName: String,
    ArrivingTerminalName: String,
}

#[allow(non_snake_case)]
#[derive(RustcDecodable, RustcEncodable, Debug)]
struct Schedule {
    TerminalCombos: Vec<TerminalCombo>,
}

type Result<T> = result::Result<T, CliError>;

#[derive(Debug)]
enum CliError {
    Log(log::SetLoggerError),
    Parse(rustc_serialize::json::DecoderError),
    SaveCache(rustc_serialize::json::EncoderError),
    Http(hyper::error::Error),
    Io(std::io::Error),
    BadInput(String),
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CliError::Log(ref err) => format!("Unable to configure logging: {}", err).fmt(f),
            CliError::Parse(ref err) => format!("Unable to parse WSDOT Data: {}", err).fmt(f),
            CliError::SaveCache(ref err) => format!("Unable to save cache: {}", err).fmt(f),
            CliError::Http(ref err) => format!("Unable to communicate with WSDOT: {}", err).fmt(f),
            CliError::Io(ref err) => format!("Unable to read data: {}", err).fmt(f),
            CliError::BadInput(ref desc) => format!("Unable to understand input: {}", desc).fmt(f),
        }
    }
}

impl Error for CliError {
    fn description(&self) -> &str {
        match *self {
            CliError::BadInput(ref err) => err,
            _ => self.description(),
        }
    }
}

impl From<rustc_serialize::json::EncoderError> for CliError {
    fn from(err: rustc_serialize::json::EncoderError) -> CliError {
        CliError::SaveCache(err)
    }
}

impl From<log::SetLoggerError> for CliError {
    fn from(err: log::SetLoggerError) -> CliError {
        CliError::Log(err)
    }
}
impl From<hyper::error::Error> for CliError {
    fn from(err: hyper::error::Error) -> CliError {
        CliError::Http(err)
    }
}

impl From<std::io::Error> for CliError {
    fn from(err: std::io::Error) -> CliError {
        CliError::Io(err)
    }
}

impl From<rustc_serialize::json::DecoderError> for CliError {
    fn from(err: rustc_serialize::json::DecoderError) -> CliError {
        CliError::Parse(err)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate log4rs;

#[macro_use]
extern crate lazy_static;

mod logging;
mod tcp;
mod core;

use core::StoppableCore;

fn main() {
	// read logging parameters
	logging::init_logging("config/log4rs.yaml");

	info!("starting process ");

	tcp::init();

	if false {
		logging::unittestlogger();
	}

	let core = core::StoppableCore::new().unwrap();
	let timeout = std::time::Duration::from_secs(10);
	core.run_timeout(timeout).unwrap();

	info!("ending gracefully");
}
<commit_msg>support for OpenWrt cross compilation<commit_after>#![feature(global_allocator)]
#![feature(allocator_api)]

#[macro_use]
extern crate log;
extern crate log4rs;

#[macro_use]
extern crate lazy_static;

//#![feature(alloc_system)]
//extern crate alloc_system;

use std::heap::System;

#[global_allocator]
static ALLOCATOR: System = System;

mod logging;
mod tcp;
mod core;

use core::StoppableCore;

fn main() {
	// read logging parameters
	logging::init_logging("config/log4rs.yaml");

	info!("starting process ");

	tcp::init();

	if false {
		logging::unittestlogger();
	}

	let core = core::StoppableCore::new().unwrap();
	let timeout = std::time::Duration::from_secs(10);
	core.run_timeout(timeout).unwrap();

	info!("ending gracefully");
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate libc;
extern crate neovim;
extern crate rgtk;
extern crate serialize;

use neovim::nvim_main;
use rgtk::*;
use std::collections::HashSet;
use std::{io, str, time};

mod projects;
mod ui;
mod utils;

mod ffi {
    pub use libc::{c_char, c_uchar, c_int, c_void, uint64_t};
    pub use libc::funcs::posix88::unistd::{close, pipe, read, write};
    pub use libc::types::os::arch::c95::size_t;

    extern "C" {
        pub fn fork () -> c_int;
        pub fn kill (pid: c_int, sig: c_int);
        pub fn channel_from_fds (read_fd: c_int, write_fd: c_int) -> uint64_t;
        pub fn channel_subscribe(id: uint64_t, event: *const c_char);
    }
}

fn gui_main(
    pty: &mut gtk::VtePty,
    pid: ffi::c_int,
    read_fd: ffi::c_int,
    write_fd: ffi::c_int)
{
    gtk::init();

    // constants

    let width = 1242;
    let height = 768;
    let editor_height = ((height as f32) * 0.75) as i32;

    // create the window

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    window.set_title("SolidOak");
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(width, height);

    window.connect(gtk::signals::DeleteEvent::new(|_| {
        unsafe {
            ffi::close(read_fd);
            ffi::close(write_fd);
            ffi::kill(pid, 15);
        }
        gtk::main_quit();
        true
    }));

    // create the panes

    let new_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut proj_btns = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    proj_btns.set_size_request(-1, -1);
    proj_btns.add(&new_button);
    proj_btns.add(&import_button);
    proj_btns.add(&rename_button);
    proj_btns.add(&remove_button);

    let mut proj_tree = gtk::TreeView::new().unwrap();
    let selection = proj_tree.get_selection().unwrap();
    let column_types = [glib::ffi::g_type_string, glib::ffi::g_type_string];
    let store = gtk::TreeStore::new(&column_types).unwrap();
    let model = store.get_model().unwrap();
    proj_tree.set_model(&model);
    proj_tree.set_headers_visible(false);

    let mut scroll_pane = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll_pane.add(&proj_tree);

    let column = gtk::TreeViewColumn::new().unwrap();
    let cell = gtk::CellRendererText::new().unwrap();
    column.pack_start(&cell, true);
    column.add_attribute(&cell, "text", 0);
    proj_tree.append_column(&column);

    let mut proj_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    proj_pane.set_size_request(-1, -1);
    proj_pane.pack_start(&proj_btns, false, true, 0);
    proj_pane.pack_start(&scroll_pane, true, true, 0);

    let mut editor_pane = gtk::VteTerminal::new().unwrap();
    editor_pane.set_size_request(-1, editor_height);
    editor_pane.set_pty(pty);
    editor_pane.watch_child(pid);

    let run_button = gtk::Button::new_with_label("Run").unwrap();
    let build_button = gtk::Button::new_with_label("Build").unwrap();
    let test_button = gtk::Button::new_with_label("Test").unwrap();
    let clean_button = gtk::Button::new_with_label("Clean").unwrap();
    let stop_button = gtk::Button::new_with_label("Stop").unwrap();

    let mut build_btns = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    build_btns.set_size_request(-1, -1);
    build_btns.add(&run_button);
    build_btns.add(&build_button);
    build_btns.add(&test_button);
    build_btns.add(&clean_button);
    build_btns.add(&stop_button);

    let build_term = gtk::VteTerminal::new().unwrap();

    let mut build_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    build_pane.pack_start(&build_btns, false, true, 0);
    build_pane.pack_start(&build_term, true, true, 0);

    let mut content = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    content.pack_start(&editor_pane, false, true, 0);
    content.pack_start(&build_pane, true, true, 0);

    let mut hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&proj_pane, false, true, 0);
    hbox.pack_start(&content, true, true, 0);
    window.add(&hbox);

    // populate the project tree

    let mut state = ::utils::State{
        projects: HashSet::new(),
        expansions: HashSet::new(),
        selection: None,
        tree_model: &model,
        tree_store: &store,
        tree_selection: &selection,
        rename_button: &rename_button,
        remove_button: &remove_button,
    };

    ::utils::create_data_dir();
    ::utils::read_prefs(&mut state);
    ::ui::update_project_tree(&mut state, &mut proj_tree);

    // connect to the signals

    new_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::new_project(&mut state, &mut proj_tree);
    }));
    import_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::import_project(&mut state, &mut proj_tree);
    }));
    rename_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::rename_file(&mut state);
    }));
    remove_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::remove_item(&mut state);
    }));
    selection.connect(gtk::signals::Changed::new(|| {
        ::projects::update_selection(&mut state);
    }));
    proj_tree.connect(gtk::signals::RowCollapsed::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::remove_expansion(&mut state, &iter);
    }));
    proj_tree.connect(gtk::signals::RowExpanded::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::add_expansion(&mut state, &iter);
    }));

    // show the window

    window.show_all();
    gtk::main();
}

fn main() {
    let mut pty = gtk::VtePty::new().unwrap();

    let mut nvim_from_gui : [ffi::c_int, ..2] = [0, ..2];
    let mut gui_from_nvim : [ffi::c_int, ..2] = [0, ..2];
    unsafe {
        ffi::pipe(nvim_from_gui.as_mut_ptr());
        ffi::pipe(gui_from_nvim.as_mut_ptr());
    };

    let pid = unsafe { ffi::fork() };

    if pid > 0 {
        spawn(proc() {
            let mut buf : [ffi::c_uchar, ..100] = [0, ..100];
            unsafe {
                loop {
                    let buf_ptr = buf.as_mut_ptr() as *mut ffi::c_void;
                    let n = ffi::read(gui_from_nvim[0], buf_ptr, 100);
                    if n < 0 { break; }
                    let msg = str::from_utf8(buf.slice_to(n as uint)).unwrap();
                    println!("Received: {}", msg);
                }
            }
        });
        gui_main(&mut pty, pid, gui_from_nvim[0], gui_from_nvim[1]);
    } else {
        pty.child_setup();
        spawn(proc() {
            io::timer::sleep(time::Duration::seconds(1));
            unsafe {
                let id = ffi::channel_from_fds(nvim_from_gui[0], gui_from_nvim[1]);
                let cmd = "test";
                ffi::channel_subscribe(id, cmd.to_c_str().as_ptr());

                let msg = "Hello, world!";
                let msg_c = msg.to_c_str();
                let msg_ptr = msg_c.as_ptr() as *const ffi::c_void;
                ffi::write(gui_from_nvim[1], msg_ptr, msg_c.len() as ffi::size_t);
            }
        });
        nvim_main();
    }
}
<commit_msg>Add comments<commit_after>#![feature(globs)]

extern crate libc;
extern crate neovim;
extern crate rgtk;
extern crate serialize;

use neovim::nvim_main;
use rgtk::*;
use std::collections::HashSet;
use std::{io, str, time};

mod projects;
mod ui;
mod utils;

mod ffi {
    pub use libc::{c_char, c_int, c_uchar, c_void, uint64_t};
    pub use libc::funcs::posix88::unistd::{close, pipe, read, write};
    pub use libc::types::os::arch::c95::size_t;

    extern "C" {
        pub fn fork () -> c_int;
        pub fn kill (pid: c_int, sig: c_int);
        pub fn channel_from_fds (read_fd: c_int, write_fd: c_int) -> uint64_t;
        pub fn channel_subscribe(id: uint64_t, event: *const c_char);
    }
}

fn gui_main(
    pty: &mut gtk::VtePty,
    read_fd: ffi::c_int,
    write_fd: ffi::c_int,
    pid: ffi::c_int)
{
    gtk::init();

    // constants

    let width = 1242;
    let height = 768;
    let editor_height = ((height as f32) * 0.75) as i32;

    // create the window

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    window.set_title("SolidOak");
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(width, height);

    window.connect(gtk::signals::DeleteEvent::new(|_| {
        unsafe {
            ffi::close(read_fd);
            ffi::close(write_fd);
            ffi::kill(pid, 15);
        }
        gtk::main_quit();
        true
    }));

    // create the panes

    let new_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut proj_btns = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    proj_btns.set_size_request(-1, -1);
    proj_btns.add(&new_button);
    proj_btns.add(&import_button);
    proj_btns.add(&rename_button);
    proj_btns.add(&remove_button);

    let mut proj_tree = gtk::TreeView::new().unwrap();
    let selection = proj_tree.get_selection().unwrap();
    let column_types = [glib::ffi::g_type_string, glib::ffi::g_type_string];
    let store = gtk::TreeStore::new(&column_types).unwrap();
    let model = store.get_model().unwrap();
    proj_tree.set_model(&model);
    proj_tree.set_headers_visible(false);

    let mut scroll_pane = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll_pane.add(&proj_tree);

    let column = gtk::TreeViewColumn::new().unwrap();
    let cell = gtk::CellRendererText::new().unwrap();
    column.pack_start(&cell, true);
    column.add_attribute(&cell, "text", 0);
    proj_tree.append_column(&column);

    let mut proj_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    proj_pane.set_size_request(-1, -1);
    proj_pane.pack_start(&proj_btns, false, true, 0);
    proj_pane.pack_start(&scroll_pane, true, true, 0);

    let mut editor_pane = gtk::VteTerminal::new().unwrap();
    editor_pane.set_size_request(-1, editor_height);
    editor_pane.set_pty(pty);
    editor_pane.watch_child(pid);

    let run_button = gtk::Button::new_with_label("Run").unwrap();
    let build_button = gtk::Button::new_with_label("Build").unwrap();
    let test_button = gtk::Button::new_with_label("Test").unwrap();
    let clean_button = gtk::Button::new_with_label("Clean").unwrap();
    let stop_button = gtk::Button::new_with_label("Stop").unwrap();

    let mut build_btns = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    build_btns.set_size_request(-1, -1);
    build_btns.add(&run_button);
    build_btns.add(&build_button);
    build_btns.add(&test_button);
    build_btns.add(&clean_button);
    build_btns.add(&stop_button);

    let build_term = gtk::VteTerminal::new().unwrap();

    let mut build_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    build_pane.pack_start(&build_btns, false, true, 0);
    build_pane.pack_start(&build_term, true, true, 0);

    let mut content = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    content.pack_start(&editor_pane, false, true, 0);
    content.pack_start(&build_pane, true, true, 0);

    let mut hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&proj_pane, false, true, 0);
    hbox.pack_start(&content, true, true, 0);
    window.add(&hbox);

    // populate the project tree

    let mut state = ::utils::State{
        projects: HashSet::new(),
        expansions: HashSet::new(),
        selection: None,
        tree_model: &model,
        tree_store: &store,
        tree_selection: &selection,
        rename_button: &rename_button,
        remove_button: &remove_button,
    };

    ::utils::create_data_dir();
    ::utils::read_prefs(&mut state);
    ::ui::update_project_tree(&mut state, &mut proj_tree);

    // connect to the signals

    new_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::new_project(&mut state, &mut proj_tree);
    }));
    import_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::import_project(&mut state, &mut proj_tree);
    }));
    rename_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::rename_file(&mut state);
    }));
    remove_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::remove_item(&mut state);
    }));
    selection.connect(gtk::signals::Changed::new(|| {
        ::projects::update_selection(&mut state);
    }));
    proj_tree.connect(gtk::signals::RowCollapsed::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::remove_expansion(&mut state, &iter);
    }));
    proj_tree.connect(gtk::signals::RowExpanded::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::add_expansion(&mut state, &iter);
    }));

    // show the window

    window.show_all();
    gtk::main();
}

fn main() {
    // takes care of piping stdin/stdout between the gui and nvim
    let mut pty = gtk::VtePty::new().unwrap();

    // two pairs of anonymous pipes for msgpack-rpc between the gui and nvim
    let mut nvim_from_gui : [ffi::c_int, ..2] = [0, ..2];
    let mut gui_from_nvim : [ffi::c_int, ..2] = [0, ..2];
    unsafe {
        ffi::pipe(nvim_from_gui.as_mut_ptr());
        ffi::pipe(gui_from_nvim.as_mut_ptr());
    };

    // split into two processes
    let pid = unsafe { ffi::fork() };

    if pid > 0 { // the gui process
        // listen for messages from nvim
        spawn(proc() {
            let mut buf : [ffi::c_uchar, ..100] = [0, ..100];
            unsafe {
                loop {
                    let buf_ptr = buf.as_mut_ptr() as *mut ffi::c_void;
                    let n = ffi::read(gui_from_nvim[0], buf_ptr, 100);
                    if n < 0 { break; }
                    let msg = str::from_utf8(buf.slice_to(n as uint)).unwrap();
                    println!("Received: {}", msg);
                }
            }
        });

        // start the gui
        gui_main(&mut pty, gui_from_nvim[0], gui_from_nvim[1], pid);
    } else { // the nvim process
        // prepare this process to be piped into the gui
        pty.child_setup();

        // listen for messages from the gui
        spawn(proc() {
            io::timer::sleep(time::Duration::seconds(1));
            unsafe {
                let id = ffi::channel_from_fds(nvim_from_gui[0], gui_from_nvim[1]);
                let cmd = "test";
                ffi::channel_subscribe(id, cmd.to_c_str().as_ptr());

                let msg = "Hello, world!";
                let msg_c = msg.to_c_str();
                let msg_ptr = msg_c.as_ptr() as *const ffi::c_void;
                ffi::write(gui_from_nvim[1], msg_ptr, msg_c.len() as ffi::size_t);
            }
        });

        // start nvim
        nvim_main();
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate serde_json;
extern crate vegas_lattice;

use std::error::Error;
use std::fs::File;
use std::io::{stdin, Read};
use std::path::Path;

use docopt::{ArgvMap, Docopt};
use vegas_lattice::{Axis, Lattice, Mask, Alloy};

const USAGE: &'static str = "
Vegas lattice.

Usage:
    vegas-lattice check [<input>]
    vegas-lattice compress [<input>]
    vegas-lattice drop [-x -y -z] [<input>]
    vegas-lattice alloy <source> (<target> <ratio>)... [<input>]
    vegas-lattice expand [--x=<x> --y=<y> --z=<z>] [<input>]
    vegas-lattice mask [--ppu=<ppu>] <mask> [<input>]
    vegas-lattice into xyz [<input>]
    vegas-lattice (-h | --help)
    vegas-lattice --version

Options:
    -p --ppu=<ppu>  Pixels per unit [default: 10].
    -h --help       Show this message.
    --version       Show version and exit.
";

fn read(input: &str) -> Result<Lattice, Box<Error>> {
    let mut data = String::new();
    if !input.is_empty() {
        let mut file = File::open(input)?;
        file.read_to_string(&mut data)?;
    } else {
        stdin().read_to_string(&mut data)?;
    };
    let lattice: Lattice = data.parse()?;
    Ok(lattice)
}

fn write_compressed(lattice: Lattice) {
    println!("{}", serde_json::to_string(&lattice).unwrap());
}

fn write(lattice: Lattice) {
    println!("{}", serde_json::to_string_pretty(&lattice).unwrap());
}

fn check_error(res: Result<(), Box<Error>>) {
    match res {
        Err(e) => {
            eprintln!("Error: {}", e.description());
            match e.cause() {
                Some(cause) => eprintln!("Cause: {}", cause),
                _ => ()
            };
            std::process::exit(1);
        },
        _ => {},
    }
}

// Commands over here

fn check(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write(lattice);
    Ok(())
}

fn compress(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write_compressed(lattice);
    Ok(())
}

fn drop(args: ArgvMap) -> Result<(), Box<Error>> {
    let mut lattice = read(args.get_str("<input>"))?;
    for (key, axis) in Axis::map(Some("-".to_string())) {
        if args.get_bool(&key) {
            lattice = lattice.drop(axis);
        }
    }
    write(lattice);
    Ok(())
}

fn alloy(args: ArgvMap) -> Result<(), Box<Error>> {
    let source = args.get_str("<source>");
    let kinds = args.get_vec("<target>");
    let ratios = args.get_vec("<ratio>")
        .into_iter()
        .map(|r| r.parse())
        .collect::<Result<Vec<u32>, _>>()?;
    let alloy = Alloy::new(kinds, ratios);
    let mut lattice = read(args.get_str("<input>"))?;
    lattice = lattice.alloy_sites(source, alloy);
    write(lattice);
    Ok(())
}

fn expand(args: ArgvMap) -> Result<(), Box<Error>> {
    let map = Axis::map(Some("--".to_string()));
    let mut lattice = read(args.get_str("<input>"))?;
    for (flag, axis) in map.into_iter() {
        let string_value = args.get_str(&flag);
        if !string_value.is_empty() {
            let size: usize = string_value.parse()?;
            lattice = lattice.expand_along(axis, size);
        }
    }
    write(lattice);
    Ok(())
}

fn mask(args: ArgvMap) -> Result<(), Box<Error>> {
    let path = args.get_str("<mask>");
    let ppu: f64 = args.get_str("--ppu").parse()?;
    let mask = Mask::new(&Path::new(path), ppu)?;
    let mut lattice = read(args.get_str("<input>"))?;
    lattice = lattice.apply_mask(mask);
    write(lattice);
    Ok(())
}

fn into(args: ArgvMap) -> Result<(), Box<Error>> {
    if args.get_bool("xyz") {
        let lattice = read(args.get_str("<input>"))?;
        for site in lattice.sites().iter() {
            let (x, y, z) = site.position();
            println!("{} {} {} {}", x, y, z, site.kind())
        }
    }
    Ok(())
}

fn main() {
    let args = Docopt::new(USAGE)
        .and_then(|doc| doc.version(Some("0.0.1".to_string())).parse())
        .unwrap_or_else(|e| e.exit());

    if args.get_bool("check") {
        check_error(check(args));
    } else if args.get_bool("compress") {
        check_error(compress(args));
    } else if args.get_bool("drop") {
        check_error(drop(args));
    } else if args.get_bool("alloy") {
        check_error(alloy(args));
    } else if args.get_bool("expand") {
        check_error(expand(args));
    } else if args.get_bool("mask") {
        check_error(mask(args));
    } else if args.get_bool("into") {
        check_error(into(args));
    } else {
        println!("{:?}", args);
    }
}<commit_msg>Closes #36 implement to the actual xyz spec<commit_after>extern crate docopt;
extern crate serde_json;
extern crate vegas_lattice;

use std::error::Error;
use std::fs::File;
use std::io::{stdin, Read};
use std::path::Path;

use docopt::{ArgvMap, Docopt};
use vegas_lattice::{Axis, Lattice, Mask, Alloy};

const USAGE: &'static str = "
Vegas lattice.

Usage:
    vegas-lattice check [<input>]
    vegas-lattice compress [<input>]
    vegas-lattice drop [-x -y -z] [<input>]
    vegas-lattice expand [--x=<x> --y=<y> --z=<z>] [<input>]
    vegas-lattice alloy <source> (<target> <ratio>)... [<input>]
    vegas-lattice mask [--ppu=<ppu>] <mask> [<input>]
    vegas-lattice into (xyz|tsv) [<input>]
    vegas-lattice (-h | --help)
    vegas-lattice --version

Options:
    -p --ppu=<ppu>  Pixels per unit [default: 10].
    -h --help       Show this message.
    --version       Show version and exit.
";

fn read(input: &str) -> Result<Lattice, Box<Error>> {
    let mut data = String::new();
    if !input.is_empty() {
        let mut file = File::open(input)?;
        file.read_to_string(&mut data)?;
    } else {
        stdin().read_to_string(&mut data)?;
    };
    let lattice: Lattice = data.parse()?;
    Ok(lattice)
}

fn write_compressed(lattice: Lattice) {
    println!("{}", serde_json::to_string(&lattice).unwrap());
}

fn write(lattice: Lattice) {
    println!("{}", serde_json::to_string_pretty(&lattice).unwrap());
}

fn check_error(res: Result<(), Box<Error>>) {
    match res {
        Err(e) => {
            eprintln!("Error: {}", e.description());
            match e.cause() {
                Some(cause) => eprintln!("Cause: {}", cause),
                _ => ()
            };
            std::process::exit(1);
        },
        _ => {},
    }
}

// Commands over here

fn check(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write(lattice);
    Ok(())
}

fn compress(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    write_compressed(lattice);
    Ok(())
}

fn drop(args: ArgvMap) -> Result<(), Box<Error>> {
    let mut lattice = read(args.get_str("<input>"))?;
    for (key, axis) in Axis::map(Some("-".to_string())) {
        if args.get_bool(&key) {
            lattice = lattice.drop(axis);
        }
    }
    write(lattice);
    Ok(())
}

fn expand(args: ArgvMap) -> Result<(), Box<Error>> {
    let map = Axis::map(Some("--".to_string()));
    let mut lattice = read(args.get_str("<input>"))?;
    for (flag, axis) in map.into_iter() {
        let string_value = args.get_str(&flag);
        if !string_value.is_empty() {
            let size: usize = string_value.parse()?;
            lattice = lattice.expand_along(axis, size);
        }
    }
    write(lattice);
    Ok(())
}

fn alloy(args: ArgvMap) -> Result<(), Box<Error>> {
    let source = args.get_str("<source>");
    let kinds = args.get_vec("<target>");
    let ratios = args.get_vec("<ratio>")
        .into_iter()
        .map(|r| r.parse())
        .collect::<Result<Vec<u32>, _>>()?;
    let alloy = Alloy::new(kinds, ratios);
    let mut lattice = read(args.get_str("<input>"))?;
    lattice = lattice.alloy_sites(source, alloy);
    write(lattice);
    Ok(())
}

fn mask(args: ArgvMap) -> Result<(), Box<Error>> {
    let path = args.get_str("<mask>");
    let ppu: f64 = args.get_str("--ppu").parse()?;
    let mask = Mask::new(&Path::new(path), ppu)?;
    let mut lattice = read(args.get_str("<input>"))?;
    lattice = lattice.apply_mask(mask);
    write(lattice);
    Ok(())
}

fn into(args: ArgvMap) -> Result<(), Box<Error>> {
    let lattice = read(args.get_str("<input>"))?;
    if args.get_bool("tsv") {
        for site in lattice.sites().iter() {
            let (x, y, z) = site.position();
            println!("{}\t{}\t{}\t{}", x, y, z, site.kind())
        }
    } else if args.get_bool("xyz") {
        println!("{}\n", lattice.sites().len());
        for site in lattice.sites().iter() {
            let (x, y, z) = site.position();
            println!("{} {} {} {}", site.kind(), x, y, z)
        }
    }
    Ok(())
}

fn main() {
    let args = Docopt::new(USAGE)
        .and_then(|doc| doc.version(Some("0.0.1".to_string())).parse())
        .unwrap_or_else(|e| e.exit());

    if args.get_bool("check") {
        check_error(check(args));
    } else if args.get_bool("compress") {
        check_error(compress(args));
    } else if args.get_bool("drop") {
        check_error(drop(args));
    } else if args.get_bool("alloy") {
        check_error(alloy(args));
    } else if args.get_bool("expand") {
        check_error(expand(args));
    } else if args.get_bool("mask") {
        check_error(mask(args));
    } else if args.get_bool("into") {
        check_error(into(args));
    } else {
        println!("{:?}", args);
    }
}
<|endoftext|>


<commit_before>extern crate csv;
extern crate getopts;
extern crate hipchat_client;
extern crate hipchat_export;
extern crate hyper;
extern crate time;

use getopts::Options;

use hipchat_client::Client as HipchatClient;
use hipchat_client::message::{Messages, MessagesRequest};
use hipchat_client::user::{UsersRequest};

use std::env;
use std::io::prelude::*;
use std::fs::{File, DirBuilder};

use hyper::Client as HyperClient;

use std::io;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn encode_messages(messages: &Messages) -> Result<String,()> {
    let mut wtr = csv::Writer::from_memory();
    for message in &(messages.items) {

        let user_name = match message.from {
            Some(ref from) => from.name.to_string(),
            None => "".to_string()
        };

        let file_name = match message.file {
            Some(ref file) => file.name.to_string(),
            None => "".to_string()
        };

        let tuple = (&message.date, user_name, &message.message, file_name);
        wtr.encode(tuple).expect("failed to encode");
    }
    return Ok(wtr.as_string().to_string())
}

fn download_files(messages: &Messages, out_path:&String) -> Result<(), io::Error> {
    for message in &(messages.items) {

        if message.file.is_some() {
            let http = HyperClient::new();
            let ref file = message.file.as_ref();

            let file_path = &format!("{}/{} {}", out_path, &message.date, file.unwrap().name);
            println!("Downloading file '{}' to '{}'", file.unwrap().url, file_path);

            let mut res = http.get(&file.unwrap().url).send();
            let mut attachment_file = try!(File::create(file_path));
            try!(io::copy(res.as_mut().unwrap(), &mut attachment_file));
        }
    }
    Ok(())
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.reqopt("o", "", "set output directory", "NAME");
    opts.reqopt("k", "", "hipchat API key", "KEY");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            println!("{}", f.to_string());
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let output = matches.opt_str("o");
    if !output.is_some() {
        print_usage(&program, opts);
        return;
    };

    let apikey = matches.opt_str("k");
    if !apikey.is_some() {
        print_usage(&program, opts);
        return;
    };

    let hipchat_client = HipchatClient::new("https://api.hipchat.com", apikey.unwrap());

    let max_results = 500;
    let user_request = UsersRequest{start_index: Some(0), max_results: Some(max_results), ..Default::default()};
    let users = hipchat_client.get_users(Some(&user_request)).unwrap();

    for user in &(users.items) {
        let path = &format!("{}/{}", output.as_ref().unwrap(), user.name);
        let messages_path = &format!("{}/messages", path);
        println!("Fetching messages from '{}' to '{}'", user.name, path);

        DirBuilder::new().recursive(true).create(path).unwrap();
        let mut messages_file = File::create(messages_path).unwrap();

        let mut request = MessagesRequest{
            start_index: Some(0),
            max_results: Some(max_results),
            reversed: Some(false),
            date: Some(format!("{}", time::now().rfc3339())),
            include_deleted: None,
            timezone: None,
            end_date: None};

        loop {
            let messages_option = hipchat_client.get_private_messages(user.id.to_string(), Some(&request));
            let messages = messages_option.as_ref().unwrap();

            if messages.items.is_empty()
                || messages.items.len() < max_results as usize {
                break;
            }

            let messages_encoded = encode_messages(&messages);
            if messages_encoded.is_ok() {
                messages_file.write_all(messages_encoded.as_ref().unwrap().as_bytes()).expect(&format!("failed to write to file {}", messages_path));
            }
            let downloads_res = download_files(&messages, &path);
            if downloads_res.is_err() {
                println!("Error downloading file: {:?}", downloads_res.err());
            }

            request.start_index = Some(request.start_index.unwrap() + max_results)
        }
    }
    println!("Done!");
}
<commit_msg>added rate limiting<commit_after>extern crate csv;
extern crate getopts;
extern crate hipchat_client;
extern crate hipchat_export;
extern crate hyper;
extern crate time;

use getopts::Options;

use hipchat_client::Client as HipchatClient;
use hipchat_client::message::{Messages, MessagesRequest};
use hipchat_client::user::{UsersRequest};

use std::env;
use std::io::prelude::*;
use std::fs::{File, DirBuilder};

use hyper::Client as HyperClient;

use std::io;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn encode_messages(messages: &Messages) -> Result<String,()> {
    let mut wtr = csv::Writer::from_memory();
    for message in &(messages.items) {

        let user_name = match message.from {
            Some(ref from) => from.name.to_string(),
            None => "".to_string()
        };

        let file_name = match message.file {
            Some(ref file) => file.name.to_string(),
            None => "".to_string()
        };

        let tuple = (&message.date, user_name, &message.message, file_name);
        wtr.encode(tuple).expect("failed to encode");
    }
    return Ok(wtr.as_string().to_string())
}

fn download_files(messages: &Messages, out_path:&String) -> Result<(), io::Error> {
    for message in &(messages.items) {

        if message.file.is_some() {
            let http = HyperClient::new();
            let ref file = message.file.as_ref();

            let file_path = &format!("{}/{} {}", out_path, &message.date, file.unwrap().name);
            println!("Downloading file '{}' to '{}'", file.unwrap().url, file_path);

            let mut res = http.get(&file.unwrap().url).send();
            let mut attachment_file = try!(File::create(file_path));
            try!(io::copy(res.as_mut().unwrap(), &mut attachment_file));
        }
    }
    Ok(())
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.reqopt("o", "", "set output directory", "NAME");
    opts.reqopt("k", "", "hipchat API key", "KEY");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            println!("{}", f.to_string());
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let output = matches.opt_str("o");
    if !output.is_some() {
        print_usage(&program, opts);
        return;
    };

    let apikey = matches.opt_str("k");
    if !apikey.is_some() {
        print_usage(&program, opts);
        return;
    };

    let hipchat_client = HipchatClient::new("https://api.hipchat.com", apikey.unwrap());

    let max_results = 500;
    let user_request = UsersRequest{start_index: Some(0), max_results: Some(max_results), ..Default::default()};
    let users = hipchat_client.get_users(Some(&user_request)).unwrap();

    for user in &(users.items) {
        let path = &format!("{}/{}", output.as_ref().unwrap(), user.name);
        let messages_path = &format!("{}/messages", path);
        println!("Fetching messages from '{}' to '{}'", user.name, path);

        DirBuilder::new().recursive(true).create(path).unwrap();
        let mut messages_file = File::create(messages_path).unwrap();

        let mut request = MessagesRequest{
            start_index: Some(0),
            max_results: Some(max_results),
            reversed: Some(false),
            date: Some(format!("{}", time::now().rfc3339())),
            include_deleted: None,
            timezone: None,
            end_date: None};

        loop {
            let messages_option = hipchat_client.get_private_messages(user.id.to_string(), Some(&request));
            let messages = messages_option.as_ref().unwrap();

            if messages.items.is_empty()
                || messages.items.len() < max_results as usize {
                break;
            }

            let messages_encoded = encode_messages(&messages);
            if messages_encoded.is_ok() {
                messages_file.write_all(messages_encoded.as_ref().unwrap().as_bytes()).expect(&format!("failed to write to file {}", messages_path));
            }
            let downloads_res = download_files(&messages, &path);
            if downloads_res.is_err() {
                println!("Error downloading file: {:?}", downloads_res.err());
            }

            request.start_index = Some(request.start_index.unwrap() + max_results)
        }
        std::thread::sleep(std::time::Duration::new(3, 0)); // hipchat only allows 20 calls per minute
    }
    println!("Done!");
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate hetu;

use ansi_term::Colour::Red;
use hetu::ErrorIndexRange;
use hetu::ParseError;
use hetu::Ssn;
use hetu::SsnPattern;
use std::env;
use std::io::{self, BufRead};
use std::process;

pub fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() == 1 && (&args[0] == "-h" || &args[0] == "--help") {
        help();
        return;
    }

    if args.len() > 1 && &args[0] == "-p" {
        match SsnPattern::parse(&args[1]) {
            Err(ref err) => {
                eprintln!(
                    "Error: {}\n\n  {}\n  {}",
                    err,
                    &args[1],
                    Red.paint(index_arrows(err))
                );
                process::exit(1)
            }
            Ok(pattern) => match Ssn::generate_by_pattern(&pattern) {
                Ok(ref ssn) => println!("{}", ssn),
                Err(ref err) => {
                    eprintln!("Error: {}", err);
                    process::exit(1)
                }
            },
        }
    } else if args.len() == 1 && &args[0] == "-" {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            parse(&(line.unwrap()));
        }
    } else if args.is_empty() {
        let pattern = SsnPattern::new();
        match Ssn::generate_by_pattern(&pattern) {
            Ok(ref ssn) => println!("{}", ssn),
            Err(ref err) => {
                eprintln!("Error: {}", err);
                process::exit(1)
            }
        }
    } else {
        parse(&args[0]);
    }
}

fn parse(ssn: &str) {
    match Ssn::parse(&ssn) {
        Ok(_) => (),
        Err(ref err) => {
            eprintln!(
                "Error: {}\n\n  {}\n  {}",
                err,
                &ssn,
                Red.paint(index_arrows(err))
            );
            process::exit(1)
        }
    }
}

fn help() {
    println!(
        "Validator and generator for Finnish SSN

Usage:
    hetu <ssn>
    hetu -
    hetu -p <pattern>
    hetu [options]

Options:
    -h, --help          Display this message
"
    );
}

fn index_arrows(err: &ParseError) -> String {
    let mut res: String = String::new();
    for _ in 0..err.start() {
        res.push(' ');
    }
    for _ in err.start()..err.end() {
        res.push('^');
    }
    res
}
<commit_msg>Add long form option for pattern and improve help<commit_after>extern crate ansi_term;
extern crate hetu;

use ansi_term::Colour::Red;
use hetu::ErrorIndexRange;
use hetu::ParseError;
use hetu::Ssn;
use hetu::SsnPattern;
use std::env;
use std::io::{self, BufRead};
use std::process;

pub fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() == 1 && (&args[0] == "-h" || &args[0] == "--help") {
        help();
        return;
    }

    if args.len() == 2 && (&args[0] == "-p" || &args[0] == "--pattern") {
        generate(&args[1]);
    } else if args.len() == 1 && *&args[0].starts_with("--pattern=") {
        generate(&args[0][10..]);
    } else if args.len() == 1 && &args[0] == "-" {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            parse(&(line.unwrap()));
        }
    } else if args.is_empty() {
        generate_and_print(&SsnPattern::new());
    } else {
        parse(&args[0]);
    }
}

fn generate(pattern: &str) {
    match SsnPattern::parse(pattern) {
        Err(ref err) => {
            eprintln!(
                "Error: {}\n\n  {}\n  {}",
                err,
                pattern,
                Red.paint(index_arrows(err))
            );
            process::exit(1)
        }
        Ok(pattern) => generate_and_print(&pattern),
    }
}

fn generate_and_print(pattern: &SsnPattern) {
    match Ssn::generate_by_pattern(&pattern) {
        Ok(ref ssn) => println!("{}", ssn),
        Err(ref err) => {
            eprintln!("Error: {}", err);
            process::exit(1)
        }
    }
}

fn parse(ssn: &str) {
    match Ssn::parse(&ssn) {
        Ok(_) => (),
        Err(ref err) => {
            eprintln!(
                "Error: {}\n\n  {}\n  {}",
                err,
                &ssn,
                Red.paint(index_arrows(err))
            );
            process::exit(1)
        }
    }
}

fn help() {
    println!(
        "Validator and generator for Finnish Personal Identity Code (HETU).

Usage:
    hetu <HETU>         Validate argument HETU.
    hetu -              Read input from standard input and validate.
    hetu                Generate HETU.
    hetu -p <PATTERN>   Generate HETU using pattern.

Options:
    -h, --help
            Print this help message.
    -p, --pattern <pattern>
            Generate HETU by pattern. Patterns use a question mark ('?') for wildcard and wildcards
            can appear at any location in the pattern.

Arguments:
    <HETU>
            Validate argument HETU. Use a dash ('-') to read from standard input.

Examples:
    * Validate HETU:

        $ hetu 291269-2763

    * Generate HETU by pattern:

        $ hetu -p '291269-????'
        291269-7767
"
    );
}

fn index_arrows(err: &ParseError) -> String {
    let mut res: String = String::new();
    for _ in 0..err.start() {
        res.push(' ');
    }
    for _ in err.start()..err.end() {
        res.push('^');
    }
    res
}
<|endoftext|>


<commit_before>extern crate xmltree;

#[macro_use]
mod parse;
mod svd;
mod write;

use xmltree::Element;
use svd::*;

macro_rules! try {
    ($e:expr) => {
        $e.expect(concat!(file!(), ":", line!(), " ", stringify!($e)))
    }
}

trait StringEx {
    fn fix_id(&self) -> String;
}

impl StringEx for String {
    fn fix_id(&self) -> String {
        self.replace("/", "_")
            .replace(" ", "_")
            .replace("__", "_")
            .replace("__", "_")
    }
}

trait ElementExt {
    fn get_attribute<K>(&self, k: K) -> Option<String>
        where String: PartialEq<K> + std::convert::From<K>;
    fn debug(&self);
}

impl ElementExt for Element {
    fn get_attribute<K>(&self, k: K) -> Option<String>
        where String: PartialEq<K> + std::convert::From<K>
    {
        //self.get_child(k).map(|c| try!(c.text.clone()))
        self.attributes.get(&String::from(k)).map(|v| v.clone())
    }

    fn debug(&self) {
        println!("<{} {:?}>", self.name, self.attributes);
        for c in &self.children {
            println!("{}: {:?}", c.name, c.attributes)
        }
        println!("</{}>", self.name);
    }
}

/// Parses the contents of a dslib module file (XML)
pub fn parse_module(xml: &str) -> Option<Peripheral> {
    let tree = &try!(Element::parse(xml.as_bytes()));
    parse_peripheral(tree)
}

/// Parses the contents of a dslib device file (XML)
pub fn parse_device_file(xml: &str) -> Device {
    let tree = &try!(Element::parse(xml.as_bytes()));
    parse_device(tree)
}

fn main() {
    let xml = include_str!("../targetdb/devices/CC430F5123.xml");
    let original = parse_device_file(xml);
    let out_svd = write::write_device(&original);

    let parsed = svd::parse_device(&out_svd);

    println!("{}", out_svd);

    assert_eq!(original, parsed);
}

fn parse_device(tree: &Element) -> Device {
    assert_eq!(tree.name, "device");

    Device {
        name: try!(tree.get_attribute("partnum")),
        peripherals: try!(tree.get_child("cpu"))
            .children
            .iter()
            .filter_map(parse_instance)
            .collect(),
        defaults: Defaults {
            size: Some(16),
            reset_value: Some(0x0),
            reset_mask: Some(0xffffffff),
            access: Some(Access::ReadWrite),
        },
    }
}

fn parse_instance(tree: &Element) -> Option<Peripheral> {
    assert_eq!(tree.name, "instance");

    let xmlpath = try!(tree.get_attribute("xmlpath"));
    let xml = try!(tree.get_attribute("xml"));

    use std::io::Read;
    use std::fs::File;
    use std::path::PathBuf;

    let file_path = PathBuf::from("targetdb/devices").join(xmlpath).join(xml);

    let mut file = File::open(file_path).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

    parse_module(&contents)
}

fn parse_peripheral(tree: &Element) -> Option<Peripheral> {
    assert_eq!(tree.name, "module");

    match tree.get_attribute("hidden") {
        Some(ref s) if s == "true" => {
            return None;
        }
        _ => {}
    }

    Some(Peripheral {
             name: try!(tree.get_attribute("id")).fix_id(),
             group_name: tree.get_attribute("id"),
             description: tree.get_attribute("description"),
             base_address: 0,
             interrupt: vec![],
             registers: Some(tree.children
                                 .iter()
                                 .filter_map(parse_register)
                                 .collect::<Vec<_>>()),
             derived_from: None,
         })
}

fn parse_register(tree: &Element) -> Option<Register> {
    let r = parse_register_info(tree);
    Some(Register::Single(r))
}

fn parse_register_info(tree: &Element) -> RegisterInfo {
    assert_eq!(tree.name, "register");

    RegisterInfo {
        name: try!(tree.get_attribute("acronym")).fix_id(),
        description: try!(tree.get_attribute("description")),
        address_offset: try!(parse::u32_str(&try!(tree.get_attribute("offset")))),
        size: parse::u32_str(&try!(tree.get_attribute("width"))),
        access: None,
        reset_value: None,
        reset_mask: None,
        fields: match tree.children.len() {
            0 => None,
            _ => {
                Some(tree.children
                         .iter()
                         .map(parse_field)
                         .collect::<Vec<_>>())
            }
        },
        write_constraint: None,
    }
}

fn parse_field(tree: &Element) -> Field {
    assert_eq!(tree.name, "bitfield");

    Field {
        name: try!(tree.get_attribute("id")).fix_id(),
        description: tree.get_attribute("description"),
        bit_range: BitRange {
            offset: try!(parse::u32_str(&try!(tree.get_attribute("begin")))),
            width: try!(parse::u32_str(&try!(tree.get_attribute("width")))),
        },
        access: tree.get_attribute("rwaccess").map(parse_access),
        enumerated_values: match tree.children.len() {
            0 => vec![],
            _ => {
                vec![EnumeratedValues {
                         name: None,
                         usage: None,
                         derived_from: None,
                         values: tree.children
                             .iter()
                             .map(parse_enum)
                             .collect::<Vec<_>>(),
                     }]
            }
        },
        write_constraint: None,
    }
}

fn parse_access(text: String) -> Access {
    match text.as_str() {
        "RW" => Access::ReadWrite,
        "RO" => Access::ReadOnly,
        _ => panic!("bad access"),
    }
}

fn parse_enum(tree: &Element) -> EnumeratedValue {
    assert_eq!(tree.name, "bitenum");

    EnumeratedValue {
        name: try!(tree.get_attribute("id")).fix_id(),
        description: tree.get_attribute("description"),
        value: parse::u32_str(&try!(tree.get_attribute("value"))),
        is_default: None,
    }
}
<commit_msg>fixed base address<commit_after>extern crate xmltree;

#[macro_use]
mod parse;
mod svd;
mod write;

use xmltree::Element;
use svd::*;

macro_rules! try {
    ($e:expr) => {
        $e.expect(concat!(file!(), ":", line!(), " ", stringify!($e)))
    }
}

trait StringEx {
    fn fix_id(&self) -> String;
}

impl StringEx for String {
    fn fix_id(&self) -> String {
        self.replace("/", "_")
            .replace(" ", "_")
            .replace("__", "_")
            .replace("__", "_")
    }
}

trait ElementExt {
    fn get_attribute<K>(&self, k: K) -> Option<String>
        where String: PartialEq<K> + std::convert::From<K>;
    fn debug(&self);
}

impl ElementExt for Element {
    fn get_attribute<K>(&self, k: K) -> Option<String>
        where String: PartialEq<K> + std::convert::From<K>
    {
        //self.get_child(k).map(|c| try!(c.text.clone()))
        self.attributes.get(&String::from(k)).map(|v| v.clone())
    }

    fn debug(&self) {
        println!("<{} {:?}>", self.name, self.attributes);
        for c in &self.children {
            println!("{}: {:?}", c.name, c.attributes)
        }
        println!("</{}>", self.name);
    }
}

/// Parses the contents of a dslib module file (XML)
pub fn parse_module(xml: &str) -> Option<Peripheral> {
    let tree = &try!(Element::parse(xml.as_bytes()));
    parse_peripheral(tree)
}

/// Parses the contents of a dslib device file (XML)
pub fn parse_device_file(xml: &str) -> Device {
    let tree = &try!(Element::parse(xml.as_bytes()));
    parse_device(tree)
}

fn main() {
    let xml = include_str!("../targetdb/devices/CC430F5123.xml");
    let original = parse_device_file(xml);
    let out_svd = write::write_device(&original);

    let parsed = svd::parse_device(&out_svd);

    println!("{}", out_svd);

    assert_eq!(original, parsed);
}

fn parse_device(tree: &Element) -> Device {
    assert_eq!(tree.name, "device");

    Device {
        name: try!(tree.get_attribute("partnum")),
        peripherals: try!(tree.get_child("cpu"))
            .children
            .iter()
            .filter_map(parse_instance)
            .collect(),
        defaults: Defaults {
            size: Some(16),
            reset_value: Some(0x0),
            reset_mask: Some(0xffff),
            access: Some(Access::ReadWrite),
        },
    }
}

fn parse_instance(tree: &Element) -> Option<Peripheral> {
    assert_eq!(tree.name, "instance");

    let xmlpath = try!(tree.get_attribute("xmlpath"));
    let xml = try!(tree.get_attribute("xml"));

    use std::io::Read;
    use std::fs::File;
    use std::path::PathBuf;

    let file_path = PathBuf::from("targetdb/devices").join(xmlpath).join(xml);

    let mut file = File::open(file_path).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

    parse_module(&contents)
}

fn parse_peripheral(tree: &Element) -> Option<Peripheral> {
    assert_eq!(tree.name, "module");

    match tree.get_attribute("hidden") {
        Some(ref s) if s == "true" => {
            return None;
        }
        _ => {}
    }

    let base_address = tree.children.iter().map(|x| {
        try!(parse::u32_str(&try!(x.get_attribute("offset"))))
    }).min().unwrap();

    Some(Peripheral {
             name: try!(tree.get_attribute("id")).fix_id(),
             group_name: tree.get_attribute("id"),
             description: tree.get_attribute("description"),
             base_address: base_address,
             interrupt: vec![],
             registers: Some(tree.children
                                 .iter()
                                 .filter_map(|x| parse_register(x, base_address))
                                 .collect::<Vec<_>>()),
             derived_from: None,
         })
}

fn parse_register(tree: &Element, base_address: u32) -> Option<Register> {
    let r = parse_register_info(tree, base_address);
    Some(Register::Single(r))
}

fn parse_register_info(tree: &Element, base_address: u32) -> RegisterInfo {
    assert_eq!(tree.name, "register");

    RegisterInfo {
        name: try!(tree.get_attribute("acronym")).fix_id(),
        description: try!(tree.get_attribute("description")),
        address_offset: try!(parse::u32_str(&try!(tree.get_attribute("offset")))) - base_address,
        size: parse::u32_str(&try!(tree.get_attribute("width"))),
        access: None,
        reset_value: None,
        reset_mask: None,
        fields: match tree.children.len() {
            0 => None,
            _ => {
                Some(tree.children
                         .iter()
                         .map(parse_field)
                         .collect::<Vec<_>>())
            }
        },
        write_constraint: None,
    }
}

fn parse_field(tree: &Element) -> Field {
    assert_eq!(tree.name, "bitfield");

    Field {
        name: try!(tree.get_attribute("id")).fix_id(),
        description: tree.get_attribute("description"),
        bit_range: BitRange {
            offset: try!(parse::u32_str(&try!(tree.get_attribute("begin")))),
            width: try!(parse::u32_str(&try!(tree.get_attribute("width")))),
        },
        access: tree.get_attribute("rwaccess").map(parse_access),
        enumerated_values: match tree.children.len() {
            0 => vec![],
            _ => {
                vec![EnumeratedValues {
                         name: None,
                         usage: None,
                         derived_from: None,
                         values: tree.children
                             .iter()
                             .map(parse_enum)
                             .collect::<Vec<_>>(),
                     }]
            }
        },
        write_constraint: None,
    }
}

fn parse_access(text: String) -> Access {
    match text.as_str() {
        "RW" => Access::ReadWrite,
        "RO" => Access::ReadOnly,
        _ => panic!("bad access"),
    }
}

fn parse_enum(tree: &Element) -> EnumeratedValue {
    assert_eq!(tree.name, "bitenum");

    EnumeratedValue {
        name: try!(tree.get_attribute("id")).fix_id(),
        description: tree.get_attribute("description"),
        value: parse::u32_str(&try!(tree.get_attribute("value"))),
        is_default: None,
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Glutin_Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::Button::{ Keyboard };
use piston::input::Input;
use piston::input::keyboard::Key;
use std::path::Path;

use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
    should_redraw: bool
}

const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        self.should_redraw = false;

        const CELL_SIZE: f64 = 30.0;
        const LEFT_MARGIN: f64 = 20f64;
        const TOP_MARGIN: f64 = 30f64;

        const STATUS_LEFT_MARGIN: f64 = 400f64;
        const STATUS_TOP_MARGIN: f64 = 100f64;
        const LINE_HEIGHT: f64 = 40f64;
        const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

        // so that we can access inside clojure
        let use_cache = &mut self.cache;
        let use_tetris = &mut self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(22);
            text.color = ORANGE;
            let mut transform = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            // render the next shape as a preview of what's coming next
            for point in use_tetris.get_next_shape().iter() {
                let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE);
                let color = get_shape_color(use_tetris.get_next_shape_index() as i32);
                // render the shape at col 2 and row 2
                let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                    (2 as i16 + point.y) as f64 * CELL_SIZE);
                graphics::rectangle(color, square, transform.trans(x, y).transform, gl);
                let tetromino_border = graphics::Rectangle::new_border(DARK_GRAY, 1.0);
                tetromino_border.draw([0f64, 0f64, CELL_SIZE, CELL_SIZE], &c.draw_state,
                    transform.trans(x, y).transform, gl);
            }
            transform = transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                text.draw(&"GAME OVER", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'N' for a new game", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Use arrow keys to move and rotate", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press spacebar to drop", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&format!("Press 'K' to decrease starting level ({})", use_tetris.get_starting_level()),
                    use_cache, &c.draw_state, transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&format!("Press 'L' to increase starting level ({})", use_tetris.get_starting_level()),
                    use_cache, &c.draw_state, transform.transform, gl);
                // uncomment if drawing additional text in the status area
                //transform = transform.trans(0f64, LINE_HEIGHT);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(WHITE, 1.5);
            rect_border.draw([
                LEFT_MARGIN,
                TOP_MARGIN,
                (CELL_SIZE * COL_COUNT as f64) + 1f64,
                (CELL_SIZE * ROW_COUNT as f64) + 1f64,
            ], &c.draw_state, c.transform, gl);

            // render each cell in the game board
            for col in 0..COL_COUNT as i32 {
                for row in 0..ROW_COUNT as i32 {
                    let cell = use_tetris.get_grid_cell(col, row);
                    if cell.cell_type != GridCellType::Void {
                        let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                        let square = graphics::rectangle::square(0.0f64, 0.0f64, CELL_SIZE);
                        let color = match cell.cell_type {
                            GridCellType::Shape => get_shape_color(cell.shape_index),
                            GridCellType::Fixed => get_shape_color(cell.shape_index),
                            GridCellType::Ghost => DARK_GRAY,
                            _ => {
                                assert!(false);
                                BLACK
                            }
                        };
                        let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                        graphics::rectangle(color, square, transform, gl);
                        let tetromino_border = graphics::Rectangle::new_border(DARK_GRAY, 1.0);
                        tetromino_border.draw([0f64, 0f64, CELL_SIZE, CELL_SIZE], &c.draw_state, transform, gl);
                    }
                }
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
                self.should_redraw = true;
            }
        }
    }

    fn handle_input(&mut self, i: Input) {
        let prev_should_redraw = self.should_redraw;
        self.should_redraw = true;
        match i {
            Input::Press(Keyboard(Key::Left)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Input::Press(Keyboard(Key::Right)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Input::Press(Keyboard(Key::Up)) => {
                self.tetris.rotate(true);
            },

            Input::Press(Keyboard(Key::Down)) => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Input::Press(Keyboard(Key::Space)) => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
            },

            Input::Press(Keyboard(Key::N)) => {
                self.tetris.start_game();
            },

            Input::Press(Keyboard(Key::K)) => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Input::Press(Keyboard(Key::L)) => {
                let new_level: u32 = self.tetris.get_starting_level() + 1;
                self.tetris.set_starting_level(new_level);
            },

            _ => {
                self.should_redraw = prev_should_redraw;
            }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::_3_2;

    let window = Glutin_Window::new(
        opengl,
        WindowSettings::new("Piston Tetris", [1024, 768])
                       .exit_on_esc(true)
                       .vsync(true)
                       .samples(1)
    );

    let font_path = Path::new("FiraMono-Bold.ttf");

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
        should_redraw: true,
    };

    for e in window.events().max_fps(30).ups(30) {
        match e {
            Event::Input(i) => {
                app.handle_input(i);
            }

            Event::Render(args) if app.should_redraw => {
                app.render(&args);
            }

            Event::Update(args) => {
                app.update(&args);
            }

            _ => {}
        }
    }
}<commit_msg>let user pick starting level<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Glutin_Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::Button::{ Keyboard };
use piston::input::Input;
use piston::input::keyboard::Key;
use std::path::Path;

use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
    should_redraw: bool
}

const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        self.should_redraw = false;

        const CELL_SIZE: f64 = 30.0;
        const LEFT_MARGIN: f64 = 20f64;
        const TOP_MARGIN: f64 = 30f64;

        const STATUS_LEFT_MARGIN: f64 = 400f64;
        const STATUS_TOP_MARGIN: f64 = 100f64;
        const LINE_HEIGHT: f64 = 40f64;
        const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

        // so that we can access inside clojure
        let use_cache = &mut self.cache;
        let use_tetris = &mut self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(22);
            text.color = ORANGE;
            let mut transform = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            // render the next shape as a preview of what's coming next
            for point in use_tetris.get_next_shape().iter() {
                let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE);
                let color = get_shape_color(use_tetris.get_next_shape_index() as i32);
                // render the shape at col 2 and row 2
                let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                    (2 as i16 + point.y) as f64 * CELL_SIZE);
                graphics::rectangle(color, square, transform.trans(x, y).transform, gl);
                let tetromino_border = graphics::Rectangle::new_border(DARK_GRAY, 1.0);
                tetromino_border.draw([0f64, 0f64, CELL_SIZE, CELL_SIZE], &c.draw_state,
                    transform.trans(x, y).transform, gl);
            }
            transform = transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                text.draw(&"GAME OVER", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'N' for a new game", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Use arrow keys to move and rotate", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press spacebar to drop", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&format!("Press 'K' to decrease starting level ({})", use_tetris.get_starting_level()),
                    use_cache, &c.draw_state, transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'L' to increase starting level",
                    use_cache, &c.draw_state, transform.transform, gl);
                // uncomment if drawing additional text in the status area
                //transform = transform.trans(0f64, LINE_HEIGHT);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(WHITE, 1.5);
            rect_border.draw([
                LEFT_MARGIN,
                TOP_MARGIN,
                (CELL_SIZE * COL_COUNT as f64) + 1f64,
                (CELL_SIZE * ROW_COUNT as f64) + 1f64,
            ], &c.draw_state, c.transform, gl);

            // render each cell in the game board
            for col in 0..COL_COUNT as i32 {
                for row in 0..ROW_COUNT as i32 {
                    let cell = use_tetris.get_grid_cell(col, row);
                    if cell.cell_type != GridCellType::Void {
                        let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                        let square = graphics::rectangle::square(0.0f64, 0.0f64, CELL_SIZE);
                        let color = match cell.cell_type {
                            GridCellType::Shape => get_shape_color(cell.shape_index),
                            GridCellType::Fixed => get_shape_color(cell.shape_index),
                            GridCellType::Ghost => DARK_GRAY,
                            _ => {
                                assert!(false);
                                BLACK
                            }
                        };
                        let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                        graphics::rectangle(color, square, transform, gl);
                        let tetromino_border = graphics::Rectangle::new_border(DARK_GRAY, 1.0);
                        tetromino_border.draw([0f64, 0f64, CELL_SIZE, CELL_SIZE], &c.draw_state, transform, gl);
                    }
                }
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
                self.should_redraw = true;
            }
        }
    }

    fn handle_input(&mut self, i: Input) {
        let prev_should_redraw = self.should_redraw;
        self.should_redraw = true;
        match i {
            Input::Press(Keyboard(Key::Left)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Input::Press(Keyboard(Key::Right)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Input::Press(Keyboard(Key::Up)) => {
                self.tetris.rotate(true);
            },

            Input::Press(Keyboard(Key::Down)) => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Input::Press(Keyboard(Key::Space)) => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
            },

            Input::Press(Keyboard(Key::N)) => {
                self.tetris.start_game();
            },

            Input::Press(Keyboard(Key::K)) => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Input::Press(Keyboard(Key::L)) => {
                let new_level: u32 = self.tetris.get_starting_level() + 1;
                self.tetris.set_starting_level(new_level);
            },

            _ => {
                self.should_redraw = prev_should_redraw;
            }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::_3_2;

    let window = Glutin_Window::new(
        opengl,
        WindowSettings::new("Piston Tetris", [1024, 768])
                       .exit_on_esc(true)
                       .vsync(true)
                       .samples(1)
    );

    let font_path = Path::new("FiraMono-Bold.ttf");

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
        should_redraw: true,
    };

    for e in window.events().max_fps(60).ups(120) {
        match e {
            Event::Input(i) => {
                app.handle_input(i);
            }

            Event::Render(args) if app.should_redraw => {
                app.render(&args);
            }

            Event::Update(args) => {
                app.update(&args);
            }

            _ => {}
        }
    }
}<|endoftext|>