<commit_before>#![feature(slice_patterns)]
#![feature(custom_attribute)]
#![feature(nll)]
#![feature(stmt_expr_attributes)]
#![cfg_attr(test, feature(plugin))]
// #![cfg_attr(test, plugin(quickcheck_macros))]

extern crate num;
extern crate rug;

extern crate toml;

#[macro_use]
extern crate gfx;
extern crate gfx_core;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate lyon;

extern crate euclid;
#[macro_use]
extern crate maplit;
extern crate itertools;

// #[cfg(test)]
// #[macro_use]
// extern crate quickcheck;

mod defs;
mod math;

mod mesh_collector;
mod mesh_gen;

mod delta;
mod draw_delta;

mod camera;
mod gamestate;
mod director;
mod polyomino;
mod shape;

mod load_universe;

use std::env;

use gfx_core::Device;
use gfx_window_glutin as gfx_glutin;
use glutin::GlContext;

use euclid::TypedSize2D;

use defs::*;
use director::*;
use math::*;
use shape::*;

const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

fn universe_filename() -> String {
    let first_argument = std::env::args().nth(1);

    match first_argument {
        Some(name) => name,
        None => "universe/minimal.toml".to_string()
    }
}

pub fn main() {
    let mut events_loop = glutin::EventsLoop::new();
    let resolution = TypedSize2D::new(1024, 768);
    let builder = glutin::WindowBuilder::new()
        .with_title("Abyme".to_string())
        .with_dimensions(resolution.width, resolution.height);
    let context = glutin::ContextBuilder::new().with_vsync(true);

    let (window, mut device, mut factory, mut main_color_view, mut main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);
    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

    let logical_state = load_universe::load_universe(universe_filename());

    let mut director: Director<_> = Director::new(&mut factory, logical_state, resolution);

    let mut last_time = std::time::Instant::now();

    let mut running = true;
    while running {
        events_loop.poll_events(|e| {
            use glutin::WindowEvent::*;
            if let glutin::Event::WindowEvent { event, .. } = e {
                match event {
                    CloseRequested => {
                        running = false;
                    }

                    Resized(w, h) => {
                        gfx_glutin::update_views(&window, &mut main_color_view, &mut main_depth);
                        director.resolution = TypedSize2D::new(w, h);
                        // TODO: recalculate camera
                    }

                    KeyboardInput {
                        input:
                            glutin::KeyboardInput {
                                virtual_keycode: Some(key),
                                state: glutin::ElementState::Pressed,
                                ..
                            },
                        ..
                    } => {
                        use glutin::VirtualKeyCode::*;
                        match key {
                            Escape => running = false,
                            Space => director.game_state.do_zoom(),
                            Up => director.game_state.try_start_move(Direction::Up),
                            Down => director.game_state.try_start_move(Direction::Down),
                            Left => director.game_state.try_start_move(Direction::Left),
                            Right => director.game_state.try_start_move(Direction::Right),
                            _ => {}
                        }
                    }
                    _ => {}
                }
            }
        });

        encoder.clear(&main_color_view, BLACK);
        director.draw(&mut encoder, &main_color_view);
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();

        let delta = std::time::Instant::now().duration_since(last_time);
        last_time = std::time::Instant::now();

        director.game_state.update(delta);
    }
}
<commit_msg>Add workaround for glutin bug<commit_after>#![feature(slice_patterns)]
#![feature(custom_attribute)]
#![feature(nll)]
#![feature(stmt_expr_attributes)]
#![cfg_attr(test, feature(plugin))]
// #![cfg_attr(test, plugin(quickcheck_macros))]

extern crate num;
extern crate rug;

extern crate toml;

#[macro_use]
extern crate gfx;
extern crate gfx_core;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate lyon;

extern crate euclid;
#[macro_use]
extern crate maplit;
extern crate itertools;

// #[cfg(test)]
// #[macro_use]
// extern crate quickcheck;

mod defs;
mod math;

mod mesh_collector;
mod mesh_gen;

mod delta;
mod draw_delta;

mod camera;
mod gamestate;
mod director;
mod polyomino;
mod shape;

mod load_universe;

use std::env;

use gfx_core::Device;
use gfx_window_glutin as gfx_glutin;
use glutin::GlContext;

use euclid::TypedSize2D;

use defs::*;
use director::*;
use math::*;
use shape::*;

const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

fn universe_filename() -> String {
    let first_argument = std::env::args().nth(1);

    match first_argument {
        Some(name) => name,
        None => "universe/minimal.toml".to_string()
    }
}

pub fn main() {
    let mut events_loop = glutin::EventsLoop::new();
    let resolution = TypedSize2D::new(1024, 768);
    let builder = glutin::WindowBuilder::new()
        .with_title("Abyme".to_string())
        .with_dimensions(resolution.width, resolution.height);
    let context = glutin::ContextBuilder::new().with_vsync(true);

    let (window, mut device, mut factory, mut main_color_view, mut main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);
    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

    let logical_state = load_universe::load_universe(universe_filename());

    let mut director: Director<_> = Director::new(&mut factory, logical_state, resolution);

    let mut last_time = std::time::Instant::now();

    // TODO: temporary workaround, delete once bug is fixed
    events_loop.poll_events(|e| {});
    window.resize(resolution.width, resolution.height);

    let mut running = true;
    while running {
        events_loop.poll_events(|e| {
            use glutin::WindowEvent::*;
            if let glutin::Event::WindowEvent { event, .. } = e {
                match event {
                    CloseRequested => {
                        running = false;
                    }

                    Resized(w, h) => {
                        gfx_glutin::update_views(&window, &mut main_color_view, &mut main_depth);
                        director.resolution = TypedSize2D::new(w, h);
                        // TODO: recalculate camera
                    }

                    KeyboardInput {
                        input:
                            glutin::KeyboardInput {
                                virtual_keycode: Some(key),
                                state: glutin::ElementState::Pressed,
                                ..
                            },
                        ..
                    } => {
                        use glutin::VirtualKeyCode::*;
                        match key {
                            Escape => running = false,
                            Space => director.game_state.do_zoom(),
                            Up => director.game_state.try_start_move(Direction::Up),
                            Down => director.game_state.try_start_move(Direction::Down),
                            Left => director.game_state.try_start_move(Direction::Left),
                            Right => director.game_state.try_start_move(Direction::Right),
                            _ => {}
                        }
                    }
                    _ => {}
                }
            }
        });

        encoder.clear(&main_color_view, BLACK);
        director.draw(&mut encoder, &main_color_view);
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();

        let delta = std::time::Instant::now().duration_since(last_time);
        last_time = std::time::Instant::now();

        director.game_state.update(delta);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Mark Lee

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate hyper;
extern crate regex;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Client, Get, Server};
use hyper::header::{Accept, ContentType};
use hyper::server::{Request, Response};
use hyper::uri::RequestUri::AbsolutePath;
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{Error, Read};

const DEFAULT_SERVER_PORT: u32 = 9000;
const MIN_BUNDLER_VERSION: &'static str = "1.11.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(client: &Client, url: &str) -> Result<String, Error> {
    let mut resp = client.get(url).send().expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn latest_buildpack_release(client: &Client) -> String {
    let xml = download_url(&client, RUBY_LANGPACK_RELEASES_URL)
                  .expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    let latest_tag = atom_doc.select("entry title")
                             .expect("Could not find latest buildpack tag!");
    latest_tag.text().clone()
}

fn bundler_version_from_ruby_buildpack(client: &Client) -> Option<String> {
    let ruby_langpack_url = format!("https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
                                    latest_buildpack_release(&client));
    let ruby_file = &download_url(&client, &ruby_langpack_url[..])
                         .expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        Some(captures.at(1).expect("Capture not found?!").to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(client: &Client) -> bool {
    if let Some(buildpack_bundler_version_str) = bundler_version_from_ruby_buildpack(&client) {
        let min_version = Version::parse(MIN_BUNDLER_VERSION)
                              .expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..])
                              .expect("Could not parse new version!");
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(req: &Request) -> ContentType {
    if let Some(accept) = req.headers.get::<Accept>() {
        let mut use_json = false;
        for qitem in &accept.0 {
            let qitem_str = &format!("{}", qitem)[..];
            if qitem_str == "application/json" {
                use_json = true;
                break;
            }
        }

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect("Could not read HTML file!");
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", MIN_BUNDLER_VERSION)
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn server_port() -> String {
    match env::var_os("PORT") {
        Some(val) => {
            match val.into_string() {
                Ok(port) => port,
                _        => format!("{}", DEFAULT_SERVER_PORT),
            }
        },
        None      => format!("{}", DEFAULT_SERVER_PORT),
    }
}

fn main() {
    let server = Server::http(&format!("0.0.0.0:{}", server_port())[..]).expect("Could not create server!");
    server.handle(|req: Request, mut res: Response| {
              match req.uri {
                  AbsolutePath(ref path) => {
                      match (&req.method, &path[..]) {
                          (&Get, "/") => {
                              let client = Client::new();
                              let result = is_bundler_upgraded(&client);
                              let content_type = determine_content_type(&req);
                              let data = match &format!("{}", content_type)[..] {
                                  "application/json; charset=utf-8" => result_to_json(result),
                                  _ => result_to_html(result),
                              };
                              res.headers_mut().set(content_type);
                              res.send(data.as_bytes()).expect("Could not set response body!")
                          }
                          _ => {
                              *res.status_mut() = hyper::NotFound;
                          }
                      }
                  }
                  _ => {
                      *res.status_mut() = hyper::BadRequest;
                  }
              }
          })
          .expect("Could not set up HTTP request handler!");
}
<commit_msg>rustfmt<commit_after>// Copyright (C) 2016 Mark Lee

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate hyper;
extern crate regex;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Client, Get, Server};
use hyper::header::{Accept, ContentType};
use hyper::server::{Request, Response};
use hyper::uri::RequestUri::AbsolutePath;
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{Error, Read};

const DEFAULT_SERVER_PORT: u32 = 9000;
const MIN_BUNDLER_VERSION: &'static str = "1.11.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(client: &Client, url: &str) -> Result<String, Error> {
    let mut resp = client.get(url).send().expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn latest_buildpack_release(client: &Client) -> String {
    let xml = download_url(&client, RUBY_LANGPACK_RELEASES_URL)
                  .expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    let latest_tag = atom_doc.select("entry title")
                             .expect("Could not find latest buildpack tag!");
    latest_tag.text().clone()
}

fn bundler_version_from_ruby_buildpack(client: &Client) -> Option<String> {
    let ruby_langpack_url = format!("https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
                                    latest_buildpack_release(&client));
    let ruby_file = &download_url(&client, &ruby_langpack_url[..])
                         .expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        Some(captures.at(1).expect("Capture not found?!").to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(client: &Client) -> bool {
    if let Some(buildpack_bundler_version_str) = bundler_version_from_ruby_buildpack(&client) {
        let min_version = Version::parse(MIN_BUNDLER_VERSION)
                              .expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..])
                              .expect("Could not parse new version!");
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(req: &Request) -> ContentType {
    if let Some(accept) = req.headers.get::<Accept>() {
        let mut use_json = false;
        for qitem in &accept.0 {
            let qitem_str = &format!("{}", qitem)[..];
            if qitem_str == "application/json" {
                use_json = true;
                break;
            }
        }

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect("Could not read HTML file!");
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", MIN_BUNDLER_VERSION)
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn server_port() -> String {
    match env::var_os("PORT") {
        Some(val) => {
            match val.into_string() {
                Ok(port) => port,
                _ => format!("{}", DEFAULT_SERVER_PORT),
            }
        }
        None => format!("{}", DEFAULT_SERVER_PORT),
    }
}

fn main() {
    let server = Server::http(&format!("0.0.0.0:{}", server_port())[..])
                     .expect("Could not create server!");
    server.handle(|req: Request, mut res: Response| {
              match req.uri {
                  AbsolutePath(ref path) => {
                      match (&req.method, &path[..]) {
                          (&Get, "/") => {
                              let client = Client::new();
                              let result = is_bundler_upgraded(&client);
                              let content_type = determine_content_type(&req);
                              let data = match &format!("{}", content_type)[..] {
                                  "application/json; charset=utf-8" => result_to_json(result),
                                  _ => result_to_html(result),
                              };
                              res.headers_mut().set(content_type);
                              res.send(data.as_bytes()).expect("Could not set response body!")
                          }
                          _ => {
                              *res.status_mut() = hyper::NotFound;
                          }
                      }
                  }
                  _ => {
                      *res.status_mut() = hyper::BadRequest;
                  }
              }
          })
          .expect("Could not set up HTTP request handler!");
}
<|endoftext|>


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

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

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

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

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

fn main() {

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

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

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

    Iron::new(mount).http("localhost:3000").unwrap();
}
<commit_msg>Only list music files in browse/flatten<commit_after>extern crate core;
extern crate iron;
extern crate mount;
extern crate rustc_serialize;
extern crate staticfile;
extern crate toml;
extern crate url;

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

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

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

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

fn main() {

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

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

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

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


<commit_before>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

use std::thread;
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
const CLOCK_HZ: u64 = 50;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 8, 8, 8, 8, 64]);
  run_simulation(&mut tui, fcfs::new(), vec![64, 8, 8, 8, 8, 8, 8, 8]);
  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 32, 32, 6, 8, 8]);

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>)
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("Starting simulation using {}", scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    if scheduler.has_processes() {
      if scheduler.current_proc().unwrap().done_executing() {
        tui.debug(format!("Killing process {}", scheduler.current_proc().unwrap().name));
        scheduler.kill_current_proc();
      }
    }

    // update all the views
    tui.update();

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    if clock_tick % SYSTEM_HZ == 0 {
      tui.debug(format!("Triggering a scheduling round"));
      scheduler.schedule();

      tui.debug(format!("Current process was waiting {} ticks for CPU time", scheduler.current_proc().unwrap().waiting_time));
    }

    // simulate executing the current process
    scheduler.current_proc_mut().unwrap().record_execution();

    // increase the waiting time for every process
    scheduler.increase_waiting_times();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("Spawning {}", new_proc.name));
        scheduler.add_process(new_proc);
      }
    }

    // update the process view
    scheduler.list_processes(&mut tui);

    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<commit_msg>Show current clock tick count in debug messages<commit_after>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

use std::thread;
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
const CLOCK_HZ: u64 = 50;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 8, 8, 8, 8, 64]);
  run_simulation(&mut tui, fcfs::new(), vec![64, 8, 8, 8, 8, 8, 8, 8]);
  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 32, 32, 6, 8, 8]);

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>)
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("{:05}: Starting simulation using {}", clock_tick, scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    if scheduler.has_processes() {
      if scheduler.current_proc().unwrap().done_executing() {
        tui.debug(format!("{:05}: Killing process {}", clock_tick, scheduler.current_proc().unwrap().name));
        scheduler.kill_current_proc();
      }
    }

    // update all the views
    tui.update();

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    if clock_tick % SYSTEM_HZ == 0 {
      tui.debug(format!("{:05}: Triggering a scheduling round", clock_tick));
      scheduler.schedule();
    }

    // simulate executing the current process
    scheduler.current_proc_mut().unwrap().record_execution();

    // increase the waiting time for every process
    scheduler.increase_waiting_times();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("{:05}: Spawning {}", clock_tick, new_proc.name));
        scheduler.add_process(new_proc);
      }
    }

    // update the process view
    scheduler.list_processes(&mut tui);

    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<|endoftext|>


<commit_before>extern crate pnet;
extern crate clap;

pub mod cli;
pub mod config;

use std::thread;
use std::time::Duration;
use std::net::Ipv4Addr;

use pnet::datalink::{self, NetworkInterface};
use pnet::datalink::Channel;
use pnet::packet::ethernet::MutableEthernetPacket;
use pnet::packet::arp::MutableArpPacket;
use pnet::util::MacAddr;
use pnet::packet::ethernet::EtherTypes;
use pnet::packet::MutablePacket;
use pnet::packet::arp::{ArpHardwareTypes, ArpOperations};

use config::Config;
use cli::cli_main;

fn send_arp_reply_packet(gateway: Ipv4Addr, source_mac: MacAddr, target_ip: Ipv4Addr, target_mac: MacAddr) {
    let interfaces = datalink::interfaces();

    // Get en1 interface in osx.
    let interfaces_name_match = |iface: &NetworkInterface| iface.name == "en1";
    let interface = interfaces.into_iter().filter(interfaces_name_match).next().unwrap();

    let(mut tx, _) = match datalink::channel(&interface, Default::default()) {
        Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("Unknown channel type"),
        Err(e) => panic!("Error happened {}", e),
    };

    /// ethernet_packet = Ethernet {
    ///     destination: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
    ///     source: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     ethertype: [0x08, 0x06], // Arp(0x0806)
    ///     payload: arp_packet
    /// }
    ///
    /// arp_packet = Arp {
    ///     hardware_type: [0x00, 0x01],
    ///     protocol_type: [0x08, 0x00], // Ipv4(0x0800)
    ///     hw_addr_len: [0x06],
    ///     proto_addr_len: [0x04],
    ///     operation: [0x00, 0x02], // Reply(0x0002)
    ///     sender_hw_addr: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     sender_proto_addr: [0xc0, 0xa8, 0x00, 0x66], // Ipv4(192.168.0.102)
    ///     target_hw_addr: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], // Broadcast
    ///     target_proto_addr: [0xc0, 0xa8, 0x00, 0x65], // Ipv4(192.168.0.101)
    ///     payload: [],
    /// }

    let mut ethernet_buffer: &mut [u8] = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut ethernet_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
    ethernet_packet.set_destination(target_mac);
    ethernet_packet.set_source(source_mac);
    ethernet_packet.set_ethertype(EtherTypes::Arp);

    let mut arp_buffer: &mut [u8] = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut arp_packet = MutableArpPacket::new(&mut arp_buffer).unwrap();

    arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
    arp_packet.set_protocol_type(EtherTypes::Ipv4);
    arp_packet.set_hw_addr_len(6);
    arp_packet.set_proto_addr_len(4);
    arp_packet.set_operation(ArpOperations::Reply);
    arp_packet.set_sender_hw_addr(source_mac);
    arp_packet.set_sender_proto_addr(gateway);
    arp_packet.set_target_hw_addr(target_mac);
    arp_packet.set_target_proto_addr(target_ip);

    ethernet_packet.set_payload(arp_packet.packet_mut());

    tx.send_to(&ethernet_packet.to_immutable(), Some(interface));
}

fn main() {
    let config: Config = cli_main();
    let mut packet_count: i32 = 0;

    loop {
        send_arp_reply_packet(config.source_ip, config.source_mac, config.target_ip, config.target_mac);

        packet_count += 1;
        println!("Sent {} ARP reply packets.", packet_count);
        thread::sleep(Duration::new(5, 0));
    }
}
<commit_msg>Change variable gateway to source ip<commit_after>extern crate pnet;
extern crate clap;

pub mod cli;
pub mod config;

use std::thread;
use std::time::Duration;
use std::net::Ipv4Addr;

use pnet::datalink::{self, NetworkInterface};
use pnet::datalink::Channel;
use pnet::packet::ethernet::MutableEthernetPacket;
use pnet::packet::arp::MutableArpPacket;
use pnet::util::MacAddr;
use pnet::packet::ethernet::EtherTypes;
use pnet::packet::MutablePacket;
use pnet::packet::arp::{ArpHardwareTypes, ArpOperations};

use config::Config;
use cli::cli_main;

fn send_arp_reply_packet(source_ip: Ipv4Addr, source_mac: MacAddr, target_ip: Ipv4Addr, target_mac: MacAddr) {
    let interfaces = datalink::interfaces();

    // Get en1 interface in osx.
    let interfaces_name_match = |iface: &NetworkInterface| iface.name == "en1";
    let interface = interfaces.into_iter().filter(interfaces_name_match).next().unwrap();

    let(mut tx, _) = match datalink::channel(&interface, Default::default()) {
        Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
        Ok(_) => panic!("Unknown channel type"),
        Err(e) => panic!("Error happened {}", e),
    };

    /// ethernet_packet = Ethernet {
    ///     destination: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
    ///     source: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     ethertype: [0x08, 0x06], // Arp(0x0806)
    ///     payload: arp_packet
    /// }
    ///
    /// arp_packet = Arp {
    ///     hardware_type: [0x00, 0x01],
    ///     protocol_type: [0x08, 0x00], // Ipv4(0x0800)
    ///     hw_addr_len: [0x06],
    ///     proto_addr_len: [0x04],
    ///     operation: [0x00, 0x02], // Reply(0x0002)
    ///     sender_hw_addr: [0x28, 0xef, 0xf9, 0x5f, 0x8e, 0x2b],
    ///     sender_proto_addr: [0xc0, 0xa8, 0x00, 0x66], // Ipv4(192.168.0.102)
    ///     target_hw_addr: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], // Broadcast
    ///     target_proto_addr: [0xc0, 0xa8, 0x00, 0x65], // Ipv4(192.168.0.101)
    ///     payload: [],
    /// }

    let mut ethernet_buffer: &mut [u8] = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut ethernet_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
    ethernet_packet.set_destination(target_mac);
    ethernet_packet.set_source(source_mac);
    ethernet_packet.set_ethertype(EtherTypes::Arp);

    let mut arp_buffer: &mut [u8] = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

    let mut arp_packet = MutableArpPacket::new(&mut arp_buffer).unwrap();

    arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
    arp_packet.set_protocol_type(EtherTypes::Ipv4);
    arp_packet.set_hw_addr_len(6);
    arp_packet.set_proto_addr_len(4);
    arp_packet.set_operation(ArpOperations::Reply);
    arp_packet.set_sender_hw_addr(source_mac);
    arp_packet.set_sender_proto_addr(source_ip);
    arp_packet.set_target_hw_addr(target_mac);
    arp_packet.set_target_proto_addr(target_ip);

    ethernet_packet.set_payload(arp_packet.packet_mut());

    tx.send_to(&ethernet_packet.to_immutable(), Some(interface));
}

fn main() {
    let config: Config = cli_main();
    let mut packet_count: i32 = 0;

    loop {
        send_arp_reply_packet(config.source_ip, config.source_mac, config.target_ip, config.target_mac);

        packet_count += 1;
        println!("Sent {} ARP reply packets.", packet_count);
        thread::sleep(Duration::new(5, 0));
    }
}
<|endoftext|>


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

use docopt::Docopt;
use std::path::Path;
use std::fs::File;
use std::io::BufReader;

const USAGE: &'static str = "
enforcer for code rules

Usage:
  enforcer <glob> [-c|--clean]
  enforcer (-h | --help)
  enforcer --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --count       only count found entries
  -c --clean    clean up trailing whitespaces
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_count: bool,
    flag_clean: bool,
    arg_glob: String,
}
const HAS_TABS: u8 = 1 << 0;
const TRAILING_SPACES: u8 = 1 << 1;

fn check_file(path: &Path) -> std::io::Result<u8> {
    use std::io::prelude::*;
    use std::fs::File;
    let mut result = 0;

    let f = try!(File::open(path));
    let reader = BufReader::new(f);
    for line in reader.lines().filter_map(|result| result.ok()) {
        if line.ends_with(' ') {
            result |= TRAILING_SPACES;
        } else if line.contains("\t") {
            result |= HAS_TABS;
        } else if line.as_bytes().iter().any(|x| *x > 127) {
            println!("file {} line \"{}\" contained illegal characters", path.display(), line);
        }
        if result != 0 {
            return Ok(result);
        }
    }
    Ok(result)
}

fn clean_buf<T: std::io::BufRead + Sized>(reader: T) -> std::io::Result<String> {
    let mut cleaned : Vec<String> = Vec::new();
    for line in reader.lines().filter_map(|result| result.ok()) {
        cleaned.push(line.trim_right().to_string());
    }
    Ok(cleaned.join("\n") + "\n")
}

fn clean_file(path: &Path) -> std::io::Result<()> {
    use std::io::prelude::*;

    let f = try!(File::open(path));
    let reader = BufReader::new(f);
    let res_string = try!(clean_buf(reader));
    let mut file = try!(File::create(path));
    try!(file.write_all(res_string.as_bytes()));
    Ok(())
}

#[allow(dead_code)]
fn main() {
    use glob::glob;
    env_logger::init().unwrap();

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

    let pat = args.arg_glob.to_string();
    for entry in glob(&*pat).unwrap() {
        match entry {
            Ok(path) => {
                let check = check_file(path.as_path()).unwrap();
                if (check & HAS_TABS) > 0 {
                    println!("{} had tabs!!!", path.display());
                }
                if (check & TRAILING_SPACES) > 0 {
                    println!("{} had trailing whitespaces!!!", path.display());
                    if args.flag_clean {
                        println!("cleaning trailing whitespaces");
                        clean_file(path.as_path()).unwrap();
                    }
                }
            },
            Err(e) => println!("{:?}", e),
        }
    }
}

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

    #[test]
    fn test_clean_does_not_remove_trailing_newline() {
        let content = "1\n2\n3\n4\n5\n";
        let cleaned = clean_buf(content.as_bytes()).unwrap();
        assert!(cleaned.eq(content));
    }
    #[test]
    fn test_clean_trailing_whitespace() {
        let content = "1 \n2";
        let cleaned = clean_buf(content.as_bytes()).unwrap();
        println!("{:?}", cleaned);
        assert!(cleaned.eq("1\n2"));
    }
}

<commit_msg>read file to string buffer before processing it<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate rustc_serialize;
extern crate docopt;
extern crate glob;

use docopt::Docopt;
use std::path::Path;
use std::fs::File;
use std::io::BufReader;

const USAGE: &'static str = "
enforcer for code rules

Usage:
  enforcer <glob> [-c|--clean]
  enforcer (-h | --help)
  enforcer --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --count       only count found entries
  -c --clean    clean up trailing whitespaces
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_count: bool,
    flag_clean: bool,
    arg_glob: String,
}
const HAS_TABS: u8 = 1 << 0;
const TRAILING_SPACES: u8 = 1 << 1;

fn check_file(path: &Path) -> std::io::Result<u8> {
    use std::io::prelude::*;
    use std::fs::File;
    let mut result = 0;

    let f = try!(File::open(path));
    let reader = BufReader::new(f);
    for line in reader.lines().filter_map(|result| result.ok()) {
        if line.ends_with(' ') {
            result |= TRAILING_SPACES;
        } else if line.contains("\t") {
            result |= HAS_TABS;
        } else if line.as_bytes().iter().any(|x| *x > 127) {
            println!("file {} line \"{}\" contained illegal characters", path.display(), line);
        }
        if result != 0 {
            return Ok(result);
        }
    }
    Ok(result)
}

fn clean_string(input: &str) -> std::io::Result<String> {
    let v: Vec<&str> = input.lines_any().map(|line| line.trim_right()).collect();
    if input.ends_with("\n") {
        Ok(v.join("\n") + "\n")
    } else {
        Ok(v.join("\n"))
    }
}

fn clean_file(path: &Path) -> std::io::Result<()> {
    use std::io::prelude::*;

    let mut f = try!(File::open(path));
    let mut buffer = String::new();
    try!(f.read_to_string(&mut buffer));
    let res_string = try!(clean_string(&buffer));
    let mut file = try!(File::create(path));
    try!(file.write_all(res_string.as_bytes()));
    Ok(())
}

#[allow(dead_code)]
fn main() {
    use glob::glob;
    env_logger::init().unwrap();

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

    let pat = args.arg_glob.to_string();
    for entry in glob(&*pat).unwrap() {
        match entry {
            Ok(path) => {
                let check = check_file(path.as_path()).unwrap();
                if (check & HAS_TABS) > 0 {
                    println!("{} had tabs!!!", path.display());
                }
                if (check & TRAILING_SPACES) > 0 {
                    println!("{} had trailing whitespaces!!!", path.display());
                    if args.flag_clean {
                        println!("cleaning trailing whitespaces");
                        clean_file(path.as_path()).unwrap();
                    }
                }
            },
            Err(e) => println!("{:?}", e),
        }
    }
}

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

    #[test]
    fn test_clean_does_not_remove_trailing_newline() {
        let content = "1\n2\n3\n4\n5\n";
        let cleaned = clean_string(content).unwrap();
        assert!(cleaned.eq(content));
    }
    #[test]
    fn test_clean_trailing_whitespace() {
        let content = "1 \n2";
        let cleaned = clean_string(content).unwrap();
        println!("{:?}", cleaned);
        assert!(cleaned.eq("1\n2"));
    }
}

<|endoftext|>


<commit_before>extern crate irc;
extern crate rand;

use std::env;
use irc::client::prelude::*;
use rand::{thread_rng, sample};

fn main() {
    let mut rng = thread_rng();
    let choices = ["heads!", "tails!"];
    // let config = Config {
    //     nickname: Some(format!("pdxferris")),
    //     alt_nicks: Some(vec![format!("pdxrust-bot"), format!("pdx-rust-bot")]),
    //     server: Some(format!("irc.freenode.net")),
    //     channels: Some(vec![format!("#pdxbots"),
    //                         format!("#pdxrust")]),
    //     .. Default::default()
    // };
    // let server = IrcServer::from_config(config).unwrap();
    let server = IrcServer::new("config.json").unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // We'll just panic if there's an error.
        if &message.command[..] == "PRIVMSG" {
            if let Some(msg) = message.suffix {
                if msg.starts_with("!flip") {
                    let choice = sample(&mut rng, choices.iter(), 1);
                    server.send_privmsg(&message.args[0],
                                        &*format!("The coin goes whirling through the air... {}",
                                                  choice.get(0).unwrap())).unwrap();
                } else if msg.starts_with("!source") {
                    server.send_privmsg(&message.args[0],
                                        "Find my source on github \
                                         ( https://github.com/wraithan/pdxrust-bot ) \
                                         contribute and teach me new things!").unwrap();
                }
            }
        }
    }
}

#[test]
fn test_main() {
    main()
}
<commit_msg>refactored commands to be slightly more modular<commit_after>extern crate irc;
extern crate rand;

use irc::client::prelude::*;
use rand::{thread_rng, sample};

fn main() {
    let commands: [fn(&String) -> Option<String>; 2]= [flip, source];
    let server = IrcServer::new("config.json").unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // We'll just panic if there's an error.
        if &message.command[..] == "PRIVMSG" {
            if let Some(msg) = message.suffix {
                for command in commands.iter() {
                    if let Some(response) = command(&msg) {
                        server.send_privmsg(&message.args[0], &*response).unwrap();
                    }
                }
            }
        }
    }
}

fn flip(message: &String) -> Option<String> {
    let choices = ["heads!", "tails!"];
    let mut rng = thread_rng();
    if message.starts_with("!flip") {
        let choice = sample(&mut rng, choices.iter(), 1);
        Some(format!("The coin goes whirling through the air... {}",
                     choice.get(0).unwrap()))
    } else {
        None
    }
}

fn source(message: &String) -> Option<String> {
    if message.starts_with("!source") {
        Some("Find my source on github \
              ( https://github.com/wraithan/pdxrust-bot ) \
              contribute and teach me new things!".to_owned())
    } else {
        None
    }
}

#[test]
fn test_main() {
    main()
}
<|endoftext|>


<commit_before>mod args;
mod matching;
mod screen;
#[cfg(not(windows))] mod ansi;

use std::cmp::min;
use std::collections::HashSet;
use std::env;
use std::io::{stdin, BufRead};
use std::process;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] pub const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] pub const NEWLINE: &'static str = "\n";

const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
const TIMESTAMP: &'static str = include_str!(concat!(env!("OUT_DIR"), "/timestamp.txt"));
const TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));
const COMMIT: &'static str = include_str!(concat!(env!("OUT_DIR"), "/commit.txt"));

fn main() {
    env::set_var("RUST_BACKTRACE", "1");
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {} for {})", VERSION, TIMESTAMP, TARGET);
        } else {
            println!("heatseeker {}-{} (built {} for {})", VERSION, COMMIT, TIMESTAMP, TARGET);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search, args.filter_only);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        let desired_rows = if args.full_screen { 999 } else { 20 };
        let selections = event_loop(desired_rows, &choices, &initial_search, args.filter_only);
        print!("{}", selections);
    }
}

fn event_loop(desired_rows: u16, choices: &[&str], initial_search: &str, filter_only: bool) -> String {
    let mut search = Search::new(choices, initial_search.to_string(), filter_only);
    let mut screen = screen::new(desired_rows);

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(screen.as_mut(), &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in &keys {
            handle_key(&mut search, key, screen.visible_choices());
        }
    }

    screen.blank_screen();
    search.get_selections()
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace |
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('r') => std::panic!("This is a test backtrace"),
        Control('c') |
        Control('g') => search.cancel(),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('p') |
        Up |
        ShiftTab => search.up(visible_choices),
        Control('n') |
        Down |
        Tab => search.down(visible_choices),
        Home => search.home(),
        End => search.end(visible_choices),
        Enter => search.done(),
        PgUp => search.pgup(visible_choices),
        PgDown => search.pgdown(visible_choices),
        _ => {},
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    scroll_offset: usize,
    cursor_index: usize,
    state: SearchState,
    selections: HashSet<String>,
    filter_only: bool,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String, filter_only: bool) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices,
            query: initial_search,
            matches,
            stale: true,
            scroll_offset: 0,
            cursor_index: 0,
            state: InProgress,
            selections: HashSet::new(),
            filter_only: filter_only,
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.scroll_offset == 0;
        if self.cursor_index == 0 {
            if should_wrap {
                if match_count > visible_choices as usize {
                    self.scroll_offset = match_count - visible_choices as usize;
                    self.cursor_index = visible_choices as usize - 1;
                } else {
                    self.cursor_index = limit;
                }
            } else {
                self.scroll_offset -= 1;
            }
        } else {
            self.cursor_index -= 1;
        }
    }

    fn down(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.cursor_index + self.scroll_offset == match_count - 1;
        if self.cursor_index == limit {
            if should_wrap {
                self.cursor_index = 0;
                self.scroll_offset = 0;
            } else {
                self.scroll_offset += 1;
            }
        } else {
            self.cursor_index += 1;
        }
    }

    fn home(&mut self) {
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn end(&mut self, visible_choices: u16) {
        self.home();
        self.up(visible_choices);
    }

    fn pgup(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset == 0 && self.cursor_index == 0 {
                return;
            }
            self.up(visible_choices);
        }
    }

    fn pgdown(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset + self.cursor_index == self.matches.len() - 1 {
                return;
            }
            self.down(visible_choices);
        }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query, self.filter_only);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            for selection in &self.selections {
                ret.push_str(selection);
                ret.push_str(NEWLINE);
            }
            if ret.is_empty() {
                self.recompute_matches();
                let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
                ret.push_str(&selection);
            }
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut dyn Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.scroll_offset, search.cursor_index, &search.selections);

    let query_str: &str = &search.query;
    screen.move_cursor_to_prompt_line(2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut dyn Screen, matches: &[&str], query: &str, scroll_offset: usize, cursor_index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches[scroll_offset..].iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width();
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == cursor_index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else if highlight {
                screen.write_red(s);
            } else { screen.write(s); }
        });
        if i >= screen.visible_choices() as usize {
            return;
        }
        screen.write(NEWLINE);
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut dyn FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let mut chars_to_draw = min(chars_in_choice, max_width as usize);
    while UnicodeWidthStr::width(slice_chars(choice, 0, chars_to_draw)) > max_width as usize {
        chars_to_draw -= 1;
    }
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(slice_chars(choice, last_idx, chars_to_draw), false);
}

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

    let mut stdin = stdin.lock();
    let mut first_error = None;
    let mut suppressed = 0;
    loop {
        let mut s = String::new();
        match stdin.read_line(&mut s) {
            Ok(_) => {
                if s.is_empty() { break; }
                trim(&mut s);
                lines.push(s);
            },
            Err(e) => {
                if first_error.is_some() {
                    suppressed = suppressed + 1;
                } else {
                    first_error = Some(e);
                }
            }
        }
    }
    if first_error.is_some() {
        eprintln!("Warning: Failed to parse one or more lines (\"{}\"); {} additional error(s) suppressed", first_error.unwrap(), suppressed);
    }

    lines
}

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

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.get_unchecked(a..b) }
    }
}

#[cfg(test)]
mod tests {
    use super::{trim, delete_last_word};

    #[test]
    fn trim_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            trim(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("\n", "");
        should_become("\n\n", "");
        should_become("asdf", "asdf");
        should_become("asdf\n", "asdf");
        should_become("asdf\nasdf\n", "asdf\nasdf");
        should_become("asdf\r\n", "asdf");
    }

    #[test]
    fn delete_word_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            delete_last_word(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("a", "");
        should_become("asdf", "");
        should_become("asdf asdf asdf", "asdf asdf ");
        should_become("asdf asdf asdf ", "asdf asdf ");
        should_become("asdf asdf asdf  ", "asdf asdf ");
    }
}
<commit_msg>Add C-f/C-b as aliases for PgDown/PgUp<commit_after>mod args;
mod matching;
mod screen;
#[cfg(not(windows))] mod ansi;

use std::cmp::min;
use std::collections::HashSet;
use std::env;
use std::io::{stdin, BufRead};
use std::process;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] pub const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] pub const NEWLINE: &'static str = "\n";

const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
const TIMESTAMP: &'static str = include_str!(concat!(env!("OUT_DIR"), "/timestamp.txt"));
const TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));
const COMMIT: &'static str = include_str!(concat!(env!("OUT_DIR"), "/commit.txt"));

fn main() {
    env::set_var("RUST_BACKTRACE", "1");
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {} for {})", VERSION, TIMESTAMP, TARGET);
        } else {
            println!("heatseeker {}-{} (built {} for {})", VERSION, COMMIT, TIMESTAMP, TARGET);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search, args.filter_only);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        let desired_rows = if args.full_screen { 999 } else { 20 };
        let selections = event_loop(desired_rows, &choices, &initial_search, args.filter_only);
        print!("{}", selections);
    }
}

fn event_loop(desired_rows: u16, choices: &[&str], initial_search: &str, filter_only: bool) -> String {
    let mut search = Search::new(choices, initial_search.to_string(), filter_only);
    let mut screen = screen::new(desired_rows);

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(screen.as_mut(), &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in &keys {
            handle_key(&mut search, key, screen.visible_choices());
        }
    }

    screen.blank_screen();
    search.get_selections()
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace |
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('r') => std::panic!("This is a test backtrace"),
        Control('c') |
        Control('g') => search.cancel(),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('p') |
        Up |
        ShiftTab => search.up(visible_choices),
        Control('n') |
        Down |
        Tab => search.down(visible_choices),
        Home => search.home(),
        End => search.end(visible_choices),
        Enter => search.done(),
        Control('b') |
        PgUp => search.pgup(visible_choices),
        Control('f') |
        PgDown => search.pgdown(visible_choices),
        _ => {},
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    scroll_offset: usize,
    cursor_index: usize,
    state: SearchState,
    selections: HashSet<String>,
    filter_only: bool,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String, filter_only: bool) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices,
            query: initial_search,
            matches,
            stale: true,
            scroll_offset: 0,
            cursor_index: 0,
            state: InProgress,
            selections: HashSet::new(),
            filter_only: filter_only,
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.scroll_offset == 0;
        if self.cursor_index == 0 {
            if should_wrap {
                if match_count > visible_choices as usize {
                    self.scroll_offset = match_count - visible_choices as usize;
                    self.cursor_index = visible_choices as usize - 1;
                } else {
                    self.cursor_index = limit;
                }
            } else {
                self.scroll_offset -= 1;
            }
        } else {
            self.cursor_index -= 1;
        }
    }

    fn down(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.cursor_index + self.scroll_offset == match_count - 1;
        if self.cursor_index == limit {
            if should_wrap {
                self.cursor_index = 0;
                self.scroll_offset = 0;
            } else {
                self.scroll_offset += 1;
            }
        } else {
            self.cursor_index += 1;
        }
    }

    fn home(&mut self) {
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn end(&mut self, visible_choices: u16) {
        self.home();
        self.up(visible_choices);
    }

    fn pgup(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset == 0 && self.cursor_index == 0 {
                return;
            }
            self.up(visible_choices);
        }
    }

    fn pgdown(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset + self.cursor_index == self.matches.len() - 1 {
                return;
            }
            self.down(visible_choices);
        }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query, self.filter_only);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            for selection in &self.selections {
                ret.push_str(selection);
                ret.push_str(NEWLINE);
            }
            if ret.is_empty() {
                self.recompute_matches();
                let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
                ret.push_str(&selection);
            }
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut dyn Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.scroll_offset, search.cursor_index, &search.selections);

    let query_str: &str = &search.query;
    screen.move_cursor_to_prompt_line(2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut dyn Screen, matches: &[&str], query: &str, scroll_offset: usize, cursor_index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches[scroll_offset..].iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width();
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == cursor_index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else if highlight {
                screen.write_red(s);
            } else { screen.write(s); }
        });
        if i >= screen.visible_choices() as usize {
            return;
        }
        screen.write(NEWLINE);
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut dyn FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let mut chars_to_draw = min(chars_in_choice, max_width as usize);
    while UnicodeWidthStr::width(slice_chars(choice, 0, chars_to_draw)) > max_width as usize {
        chars_to_draw -= 1;
    }
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(slice_chars(choice, last_idx, chars_to_draw), false);
}

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

    let mut stdin = stdin.lock();
    let mut first_error = None;
    let mut suppressed = 0;
    loop {
        let mut s = String::new();
        match stdin.read_line(&mut s) {
            Ok(_) => {
                if s.is_empty() { break; }
                trim(&mut s);
                lines.push(s);
            },
            Err(e) => {
                if first_error.is_some() {
                    suppressed = suppressed + 1;
                } else {
                    first_error = Some(e);
                }
            }
        }
    }
    if first_error.is_some() {
        eprintln!("Warning: Failed to parse one or more lines (\"{}\"); {} additional error(s) suppressed", first_error.unwrap(), suppressed);
    }

    lines
}

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

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.get_unchecked(a..b) }
    }
}

#[cfg(test)]
mod tests {
    use super::{trim, delete_last_word};

    #[test]
    fn trim_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            trim(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("\n", "");
        should_become("\n\n", "");
        should_become("asdf", "asdf");
        should_become("asdf\n", "asdf");
        should_become("asdf\nasdf\n", "asdf\nasdf");
        should_become("asdf\r\n", "asdf");
    }

    #[test]
    fn delete_word_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            delete_last_word(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("a", "");
        should_become("asdf", "");
        should_become("asdf asdf asdf", "asdf asdf ");
        should_become("asdf asdf asdf ", "asdf asdf ");
        should_become("asdf asdf asdf  ", "asdf asdf ");
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use std::io;
use std::str;
use std::collections::BTreeMap;
use tokio_core::io::{Codec, EasyBuf};
use tokio_core::io::{Io, Framed};
use tokio_core::net::TcpStream;
use tokio_proto::pipeline::ServerProto;
use tokio_proto::TcpServer;
use tokio_service::Service;
use futures::{future, Future, BoxFuture};

pub struct CliCodec {
    /// Description of the I/O object for the info command
    info: String,

    /// Offset within the incoming EasyBuf at which newline search last ended
    search_offset: usize,
}

impl CliCodec {
    /// Initializes with the given connection info
    fn new(io_info: String) -> CliCodec {
        CliCodec { info: io_info, search_offset: 0 }
    }
}

impl Codec for CliCodec {
    /// Input type is a tuple with the I/O info, the command name, and an optional argument string
    type In = (String, String, Option<String>);

    /// Response type is just a string
    type Out = String;

    /// Find a newline, decode to a tuple of command name and argument string
    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        // Find newline
        let m = buf
            .as_slice()
            .iter()
            .skip(self.search_offset)
            .position(|&b| b == b'\n');

        match m {
            // Process the line if a newline was found
            Some(idx) => {
                println!("Found newline at position {}, started at {}", idx, self.search_offset); // XXX

                let line = buf.drain_to(self.search_offset + idx);
                buf.drain_to(1);

                self.search_offset = 0;

                match str::from_utf8(line.as_slice()) {
                    // Return the string on successful UTF-8 decode
                    // (TODO: ignore blank lines)
                    Ok(s) => {
                        // TODO: Find a better way to split the string
                        let s = s.trim();

                        let request = match s.find(' ') {
                            Some(i) => {
                                let (cmd, args) = s.split_at(i);
                                (
                                    self.info.clone(),
                                    cmd.trim().to_string(),
                                    Some(args.trim().to_string())
                                )
                            },
                            None => (self.info.clone(), s.to_string(), None)
                        };

                        Ok(Some(request))
                    },

                    // Return an error if invalid UTF-8 is received
                    Err(e) => Err(io::Error::new(io::ErrorKind::Other, format!("invalid UTF-8: {:?}", e))),
                }
            },

            // Save our position if a newline wasn't found
            _ => {
                println!("Haven't received newline yet!  We started at offset {}, now at {}", self.search_offset, buf.len()); // XXX

                self.search_offset = buf.len();

                Ok(None)
            }
        }
    }

    /// Append the String to the outgoing buffer
    fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(msg.as_bytes());
        buf.extend("\n> ".as_bytes());
        Ok(())
    }
}

pub struct CliProto;

impl ServerProto<TcpStream> for CliProto {
    type Request = (String, String, Option<String>);
    type Response = String;

    type Transport = Framed<TcpStream, CliCodec>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: TcpStream) -> Self::BindTransport {
        let addr = io.peer_addr().unwrap();
        let info = format!("Client address: {}\nClient port: {}", addr.ip(), addr.port());
        Ok(io.framed(CliCodec::new(info)))
    }
}

trait CliCommand {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn call(&self, info: String, args: Option<String>) -> String;
}

#[derive(Default)]
pub struct CliServer<'a> {
    commands: BTreeMap<&'a str, &'a CliCommand>,
}

impl<'a> CliServer<'a> {
    fn new() -> CliServer<'a> {
        CliServer { commands: BTreeMap::new() }
    }

    fn add_command(&mut self, cmd: &'a CliCommand) {
        self.commands.insert(cmd.name(), cmd);
    }
}

impl<'a> Service for CliServer<'a> {
    type Request = (String, String, Option<String>);
    type Response = String;

    type Error = io::Error;

    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        let (info, cmdname, args) = req;

        match self.commands.get(&cmdname[..]) {
            Some(cmd) => {
                println!("Calling command {} for IO info {:?}", cmdname, info);
                // TODO: have commands return futures?
                future::ok(cmd.call(info, args)).boxed()
            },
            None => {
                println!("No match found for command {}", cmdname);
                future::ok(format!("Unknown command: {}", cmdname)).boxed()
            }
        }
    }
}

// TODO: Consider registering commands by passing two strings and a closure
struct EchoCommand;
impl CliCommand for EchoCommand {
    fn name(&self) -> &str {
        "echo"
    }

    fn description(&self) -> &str {
        "Prints the command line."
    }

    fn call(&self, _info: String, args: Option<String>) -> String {
        match args {
            Some(s) => s,
            None => "".to_string()
        }
    }
}

struct InfoCommand;
impl CliCommand for InfoCommand {
    fn name(&self) -> &str { "info" }
    fn description(&self) -> &str { "Prints connection information." }

    fn call(&self, info: String, _args: Option<String>) -> String {
        info
    }
}

static ECHO: EchoCommand = EchoCommand;
static INFO: InfoCommand = InfoCommand;

fn main() {
    let addr = "0.0.0.0:14311".parse().unwrap();
    let server = TcpServer::new(CliProto, addr);

    println!("Serving on {}", addr);
    server.serve(|| {
        let mut cli = CliServer::new();
        cli.add_command(&ECHO);
        cli.add_command(&INFO);
        Ok(cli)
    });
}
<commit_msg>Implemented the help command.<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use std::io;
use std::str;
use std::collections::BTreeMap;
use tokio_core::io::{Codec, EasyBuf};
use tokio_core::io::{Io, Framed};
use tokio_core::net::TcpStream;
use tokio_proto::pipeline::ServerProto;
use tokio_proto::TcpServer;
use tokio_service::Service;
use futures::{future, Future, BoxFuture};

pub struct CliCodec {
    /// Description of the I/O object for the info command
    info: String,

    /// Offset within the incoming EasyBuf at which newline search last ended
    search_offset: usize,
}

impl CliCodec {
    /// Initializes with the given connection info
    fn new(io_info: String) -> CliCodec {
        CliCodec { info: io_info, search_offset: 0 }
    }
}

impl Codec for CliCodec {
    /// Input type is a tuple with the I/O info, the command name, and an optional argument string
    type In = (String, String, Option<String>);

    /// Response type is just a string
    type Out = String;

    /// Find a newline, decode to a tuple of command name and argument string
    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        // Find newline
        let m = buf
            .as_slice()
            .iter()
            .skip(self.search_offset)
            .position(|&b| b == b'\n');

        match m {
            // Process the line if a newline was found
            Some(idx) => {
                println!("Found newline at position {}, started at {}", idx, self.search_offset); // XXX

                let line = buf.drain_to(self.search_offset + idx);
                buf.drain_to(1);

                self.search_offset = 0;

                match str::from_utf8(line.as_slice()) {
                    // Return the string on successful UTF-8 decode
                    // (TODO: ignore blank lines)
                    Ok(s) => {
                        // TODO: Find a better way to split the string
                        let s = s.trim();

                        let request = match s.find(' ') {
                            Some(i) => {
                                let (cmd, args) = s.split_at(i);
                                (
                                    self.info.clone(),
                                    cmd.trim().to_string(),
                                    Some(args.trim().to_string())
                                )
                            },
                            None => (self.info.clone(), s.to_string(), None)
                        };

                        Ok(Some(request))
                    },

                    // Return an error if invalid UTF-8 is received
                    Err(e) => Err(io::Error::new(io::ErrorKind::Other, format!("invalid UTF-8: {:?}", e))),
                }
            },

            // Save our position if a newline wasn't found
            _ => {
                println!("Haven't received newline yet!  We started at offset {}, now at {}", self.search_offset, buf.len()); // XXX

                self.search_offset = buf.len();

                Ok(None)
            }
        }
    }

    /// Append the String to the outgoing buffer
    fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(msg.as_bytes());
        buf.extend("\n> ".as_bytes());
        Ok(())
    }
}

pub struct CliProto;

impl ServerProto<TcpStream> for CliProto {
    type Request = (String, String, Option<String>);
    type Response = String;

    type Transport = Framed<TcpStream, CliCodec>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: TcpStream) -> Self::BindTransport {
        let addr = io.peer_addr().unwrap();
        let info = format!("Client address: {}\nClient port: {}", addr.ip(), addr.port());
        Ok(io.framed(CliCodec::new(info)))
    }
}

trait CliCommand {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn call(&self, server: &CliServer, info: String, args: Option<String>) -> String;
}

#[derive(Default)]
pub struct CliServer<'a> {
    commands: BTreeMap<&'a str, &'a CliCommand>,
}

impl<'a> CliServer<'a> {
    fn new() -> CliServer<'a> {
        CliServer { commands: BTreeMap::new() }
    }

    fn add_command(&mut self, cmd: &'a CliCommand) {
        self.commands.insert(cmd.name(), cmd);
    }
}

impl<'a> Service for CliServer<'a> {
    type Request = (String, String, Option<String>);
    type Response = String;

    type Error = io::Error;

    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        let (info, cmdname, args) = req;

        match self.commands.get(&cmdname[..]) {
            Some(cmd) => {
                println!("Calling command {} for IO info {:?}", cmdname, info);
                // TODO: have commands return futures?
                future::ok(cmd.call(&self, info, args)).boxed()
            },
            None => {
                println!("No match found for command {}", cmdname);
                future::ok(format!("Unknown command: {}", cmdname)).boxed()
            }
        }
    }
}

// TODO: Consider registering commands by passing two strings and a closure
struct EchoCommand;
impl CliCommand for EchoCommand {
    fn name(&self) -> &str {
        "echo"
    }

    fn description(&self) -> &str {
        "Prints the command line."
    }

    fn call(&self, _server: &CliServer, _info: String, args: Option<String>) -> String {
        match args {
            Some(s) => s,
            None => "".to_string()
        }
    }
}

struct InfoCommand;
impl CliCommand for InfoCommand {
    fn name(&self) -> &str { "info" }
    fn description(&self) -> &str { "Prints connection information." }

    fn call(&self, _server: &CliServer, info: String, _args: Option<String>) -> String {
        info
    }
}

struct HelpCommand;
impl CliCommand for HelpCommand {
    fn name(&self) -> &str { "help" }
    fn description(&self) -> &str { "Prints a list of commands and their descriptions." }

    fn call(&self, server: &CliServer, _info: String, _args: Option<String>) -> String {
        server.commands.values().map(|cmd| {
            format!("{}: {}", cmd.name(), cmd.description())
        }).collect::<Vec<_>>().as_slice().join("\n")
    }
}

static ECHO: EchoCommand = EchoCommand;
static INFO: InfoCommand = InfoCommand;
static HELP: HelpCommand = HelpCommand;

fn main() {
    let addr = "0.0.0.0:14311".parse().unwrap();
    let server = TcpServer::new(CliProto, addr);

    println!("Serving on {}", addr);
    server.serve(|| {
        // TODO: Find a way to build the server only once?
        let mut cli = CliServer::new();
        cli.add_command(&ECHO);
        cli.add_command(&INFO);
        cli.add_command(&HELP);

        Ok(cli)
    });
}
<|endoftext|>


<commit_before>extern crate automata;

//use std::process;
use automata::automata::dfa::*;

fn main() {
    // (ab)*c
    let model =
        "0\n\
         3\n\
         a 0 1\n\
         c 0 3\n\
         b 1 2\n\
         a 2 1\n\
         c 2 3\n";
    match DFA::new_from_file(&model) {
        Ok(d) => {
            let dfa = d;
            println!("{}", dfa);
            println!("{:?}", dfa.run("ababac"));
            println!("{:?}", dfa.run("ababc"));
            println!("{:?}", dfa.run(""));
            println!("{:?}", dfa.run("abc"));
            println!("{:?}", dfa.run("ac"));
            println!("{:?}", dfa.run("c"));
            println!("{:?}", dfa.run("ababababababababababababababababababababc"));
        },
        Err(e) => {
            println!("{}", e);
            //process::exit(0)
        },
    }
}
<commit_msg>remove cariage return<commit_after>extern crate automata;

//use std::process;
use automata::automata::dfa::*;

fn main() {
    // (ab)*c
    let model =
        "0\n\
         3\n\
         a 0 1\n\
         c 0 3\n\
         b 1 2\n\
         a 2 1\n\
         c 2 3";
    match DFA::new_from_file(&model) {
        Ok(d) => {
            let dfa = d;
            println!("{}", dfa);
            println!("{:?}", dfa.run("ababac"));
            println!("{:?}", dfa.run("ababc"));
            println!("{:?}", dfa.run(""));
            println!("{:?}", dfa.run("abc"));
            println!("{:?}", dfa.run("ac"));
            println!("{:?}", dfa.run("c"));
            println!("{:?}", dfa.run("ababababababababababababababababababababc"));
        },
        Err(e) => {
            println!("{}", e);
            //process::exit(0)
        },
    }
}
<|endoftext|>