<commit_before>// Copyright (c) 2016, Matthew O'Connor
extern crate system_zero_core;
use system_zero_core::ast::*;

fn constant<'input>(c: Const) -> Expr<'input> {
  Expr::constant(c)
}

fn var<'input>(v: &Var<'input>) -> Expr<'input> {
  Expr::var(v)
}

fn lam<'input>(var: Var<'input>,
               ty: Expr<'input>,
               body: Expr<'input>)
               -> Expr<'input> {
  Expr::lam(var, ty, body)
}

fn pi<'input>(var: Var<'input>,
              ty: Expr<'input>,
              body: Expr<'input>)
              -> Expr<'input> {
  Expr::pi(var, ty, body)
}

fn app<'input>(f: Expr<'input>, arg: Expr<'input>) -> Expr<'input> {
  Expr::app(f, arg)
}

fn main() {
  let v_bool = Var::new("bool", 0);
  let v_true = Var::new("true", 0);
  let v_false = Var::new("false", 0);
  let v_if = Var::new("if", 0);
  let v_b = Var::new("b", 0);
  let v_r = Var::new("r", 0);
  let v_x = Var::new("x", 0);
  let v_y = Var::new("y", 0);
  let v_0 = Var::new("0", 0);
  let v_1 = Var::new("1", 0);
  let v_nat = Var::new("nat", 0);
  let v_and = Var::new("and", 0);
  let v_or = Var::new("or", 0);
  let v_xor = Var::new("xor", 0);
  let v_not = Var::new("not", 0);
  let unused = Var::new("", 0);

  let ty_bool = constant(Const::Data);
  println!("bool : {:?}.", ty_bool);
  let ty_true = var(&v_bool);
  println!("true : {:?}.", ty_true);
  let ty_false = var(&v_bool);
  println!("false : {:?}.", ty_false);
  let ty_if = lam(unused.clone(),
                  var(&v_bool),
                  pi(v_r.clone(),
                     constant(Const::Data),
                     lam(unused.clone(),
                         var(&v_r),
                         lam(unused.clone(), var(&v_r), var(&v_r)))));
  println!("if : {:?}.", ty_if);
  println!("");

  let impl_bool = pi(v_r.clone(),
                     constant(Const::Data),
                     lam(unused.clone(),
                         var(&v_r),
                         lam(unused.clone(), var(&v_r), var(&v_r))));
  println!("bool = {:?}.", impl_bool);
  let impl_true = pi(v_r.clone(),
                     constant(Const::Data),
                     lam(v_x.clone(),
                         var(&v_r),
                         lam(unused.clone(), var(&v_r), var(&v_x))));
  println!("true = {:?}.", impl_true);
  let impl_false = pi(v_r.clone(),
                      constant(Const::Data),
                      lam(unused.clone(),
                          var(&v_r),
                          lam(v_y.clone(), var(&v_r), var(&v_y))));
  println!("false = {:?}.", impl_false);
  let impl_if = lam(v_b.clone(), var(&v_bool), var(&v_b));
  println!("if = {:?}.", impl_if);
  println!("");

  let if_true = lam(v_bool.clone(),
                    ty_bool.clone(),
                    lam(v_true.clone(),
                        ty_true.clone(),
                        lam(v_false.clone(),
                            ty_false.clone(),
                            lam(v_if.clone(),
                                ty_if.clone(),
                                app(app(app(app(var(&v_if),
                                                var(&v_true)),
                                            var(&v_nat)),
                                        var(&v_1)),
                                    var(&v_0))))));
  println!("{:?}", if_true);

  let program = if_true;
  let execute = app(app(app(app(program, impl_bool.clone()),
                            impl_true.clone()),
                        impl_false.clone()),
                    impl_if.clone());
  println!("{:?}", execute);

  let result = execute.normalize();
  println!("= {:?}", result);
  println!("");

  let p2 = lam(v_false.clone(),
               ty_false.clone(),
               app(app(app(var(&v_false), var(&v_nat)), var(&v_1)), var(&v_0)));
  println!("{:?}", p2);

  let r2 = app(p2, impl_false.clone());
  println!("{:?}", r2);
  println!("= {:?}", r2.normalize());
  println!("");

  let ty_and = lam(unused.clone(),
                   var(&v_bool),
                   lam(unused.clone(), var(&v_bool), var(&v_bool)));
  println!("and : {:?}.", ty_and);
  let impl_and = lam(v_x.clone(),
                     var(&v_bool),
                     lam(v_y.clone(),
                         var(&v_bool),
                         app(app(app(app(var(&v_if), var(&v_x)),
                                     var(&v_bool)),
                                 var(&v_y)),
                             var(&v_false))));
  println!("and = {:?}.", impl_and);
  println!("");

  let and_prog = lam(v_and.clone(),
                     ty_and.clone(),
                     app(app(var(&v_and), var(&v_true)), var(&v_false)));
  let and_prog_app = app(and_prog.clone(), impl_and.clone());
  println!("{:?}", and_prog_app);

  let ctx_bool_with_and = app(app(app(app(lam(v_bool.clone(),
                                              ty_bool.clone(),
                                              lam(v_true.clone(),
                                                  ty_true.clone(),
                                                  lam(v_false.clone(),
                                                      ty_false.clone(),
                                                      lam(v_if.clone(),
                                                          ty_if.clone(),
                                                          and_prog_app)))),
                                          impl_bool.clone()),
                                      impl_true.clone()),
                                  impl_false.clone()),
                              impl_if.clone());
  println!("{:?}", ctx_bool_with_and);
  println!("and true false = {:?}.", ctx_bool_with_and.normalize());
  println!("");
}
<commit_msg>Remove 'input lifetime parameter.<commit_after>// Copyright (c) 2016, Matthew O'Connor
extern crate system_zero_core;
use system_zero_core::ast::*;

fn constant(c: Const) -> Expr {
  Expr::constant(c)
}

fn var(v: &Var) -> Expr {
  Expr::var(v)
}

fn lam(var: Var, ty: Expr, body: Expr) -> Expr {
  Expr::lam(var, ty, body)
}

fn pi(var: Var, ty: Expr, body: Expr) -> Expr {
  Expr::pi(var, ty, body)
}

fn app(f: Expr, arg: Expr) -> Expr {
  Expr::app(f, arg)
}

fn main() {
  let v_bool = Var::new("bool", 0);
  let v_true = Var::new("true", 0);
  let v_false = Var::new("false", 0);
  let v_if = Var::new("if", 0);
  let v_b = Var::new("b", 0);
  let v_r = Var::new("r", 0);
  let v_x = Var::new("x", 0);
  let v_y = Var::new("y", 0);
  let v_0 = Var::new("0", 0);
  let v_1 = Var::new("1", 0);
  let v_nat = Var::new("nat", 0);
  let v_and = Var::new("and", 0);
  let v_or = Var::new("or", 0);
  let v_xor = Var::new("xor", 0);
  let v_not = Var::new("not", 0);
  let unused = Var::new("", 0);

  let ty_bool = constant(Const::Data);
  println!("bool : {:?}.", ty_bool);
  let ty_true = var(&v_bool);
  println!("true : {:?}.", ty_true);
  let ty_false = var(&v_bool);
  println!("false : {:?}.", ty_false);
  let ty_if = lam(unused.clone(),
                  var(&v_bool),
                  pi(v_r.clone(),
                     constant(Const::Data),
                     lam(unused.clone(),
                         var(&v_r),
                         lam(unused.clone(), var(&v_r), var(&v_r)))));
  println!("if : {:?}.", ty_if);
  println!("");

  let impl_bool = pi(v_r.clone(),
                     constant(Const::Data),
                     lam(unused.clone(),
                         var(&v_r),
                         lam(unused.clone(), var(&v_r), var(&v_r))));
  println!("bool = {:?}.", impl_bool);
  let impl_true = pi(v_r.clone(),
                     constant(Const::Data),
                     lam(v_x.clone(),
                         var(&v_r),
                         lam(unused.clone(), var(&v_r), var(&v_x))));
  println!("true = {:?}.", impl_true);
  let impl_false = pi(v_r.clone(),
                      constant(Const::Data),
                      lam(unused.clone(),
                          var(&v_r),
                          lam(v_y.clone(), var(&v_r), var(&v_y))));
  println!("false = {:?}.", impl_false);
  let impl_if = lam(v_b.clone(), var(&v_bool), var(&v_b));
  println!("if = {:?}.", impl_if);
  println!("");

  let if_true = lam(v_bool.clone(),
                    ty_bool.clone(),
                    lam(v_true.clone(),
                        ty_true.clone(),
                        lam(v_false.clone(),
                            ty_false.clone(),
                            lam(v_if.clone(),
                                ty_if.clone(),
                                app(app(app(app(var(&v_if),
                                                var(&v_true)),
                                            var(&v_nat)),
                                        var(&v_1)),
                                    var(&v_0))))));
  println!("{:?}", if_true);

  let program = if_true;
  let execute = app(app(app(app(program, impl_bool.clone()),
                            impl_true.clone()),
                        impl_false.clone()),
                    impl_if.clone());
  println!("{:?}", execute);

  let result = execute.normalize();
  println!("= {:?}", result);
  println!("");

  let p2 = lam(v_false.clone(),
               ty_false.clone(),
               app(app(app(var(&v_false), var(&v_nat)), var(&v_1)), var(&v_0)));
  println!("{:?}", p2);

  let r2 = app(p2, impl_false.clone());
  println!("{:?}", r2);
  println!("= {:?}", r2.normalize());
  println!("");

  let ty_and = lam(unused.clone(),
                   var(&v_bool),
                   lam(unused.clone(), var(&v_bool), var(&v_bool)));
  println!("and : {:?}.", ty_and);
  let impl_and = lam(v_x.clone(),
                     var(&v_bool),
                     lam(v_y.clone(),
                         var(&v_bool),
                         app(app(app(app(var(&v_if), var(&v_x)),
                                     var(&v_bool)),
                                 var(&v_y)),
                             var(&v_false))));
  println!("and = {:?}.", impl_and);
  println!("");

  let and_prog = lam(v_and.clone(),
                     ty_and.clone(),
                     app(app(var(&v_and), var(&v_true)), var(&v_false)));
  let and_prog_app = app(and_prog.clone(), impl_and.clone());
  println!("{:?}", and_prog_app);

  let ctx_bool_with_and = app(app(app(app(lam(v_bool.clone(),
                                              ty_bool.clone(),
                                              lam(v_true.clone(),
                                                  ty_true.clone(),
                                                  lam(v_false.clone(),
                                                      ty_false.clone(),
                                                      lam(v_if.clone(),
                                                          ty_if.clone(),
                                                          and_prog_app)))),
                                          impl_bool.clone()),
                                      impl_true.clone()),
                                  impl_false.clone()),
                              impl_if.clone());
  println!("{:?}", ctx_bool_with_and);
  println!("and true false = {:?}.", ctx_bool_with_and.normalize());
  println!("");
}
<|endoftext|>


<commit_before>extern crate specs;

use specs::Join;
use std::io::prelude::*;
use std::io;
use std::io::BufReader;
use std::fs::File;

static MAP: &'static str = include_str!("../map");

#[derive(Copy, Clone, Debug, PartialEq)]
struct Tile {
    c: char,
}

impl specs::Component for Tile {
    type Storage = specs::VecStorage<Tile>;
}

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

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

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

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

impl specs::Component for PlayerController {
    type Storage = specs::VecStorage<PlayerController >;
}

impl specs::Component for NonPlayerController {
    type Storage = specs::VecStorage<NonPlayerController >;
}

impl specs::Component for RenderController {
    type Storage = specs::VecStorage<RenderController >;
}

impl specs::Component for ImmovableController {
    type Storage = specs::VecStorage<ImmovableController>;
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Position {
    x: i32,
    y: i32,
}

impl specs::Component for Position {
    type Storage = specs::VecStorage<Position>;
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Velocity {
    dx: i32,
    dy: i32,
}

impl specs::Component for Velocity {
    type Storage = specs::VecStorage<Velocity>;
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Size {
    w: u32,
    h: u32,
}

impl specs::Component for Size {
    type Storage = specs::VecStorage<Size>;
}

#[derive(Clone, Debug, PartialEq)]
struct WorldMap(Vec<char>);

#[derive(Clone, Debug)]
struct Command(String);

//#[cfg(not(feature="parallel"))]
//fn main() {
//}
//
//#[cfg(feature="parallel")]
fn main() {
    let map_width = 10;
    let height = 10;
    let mut lines: Vec<&str> = MAP.lines().collect();
    let map_settings = lines.remove(0);
    for word in map_settings.split_whitespace() {
    }
    let map: Vec<char> = lines.iter().flat_map(|line| line.chars()).collect();

    let mut planner = {
        let mut w = specs::World::new();
        w.register::<Size>();
        w.register::<Tile>();
        w.register::<Position>();
        w.register::<Velocity>();
        w.register::<PlayerController>();
        w.register::<NonPlayerController>();
        w.register::<RenderController>();
        w.register::<ImmovableController>();

        // Entities
        let _player = w.create_now()
            .with(Tile { c: '😀' })
            .with(Velocity { dx: 0, dy: 0 })
            .with(Position { x: 0, y: 0 })
            .with(PlayerController)
            .with(Size { w: 1, h: 1 })
            .build();

        let _view = w.create_now()
            .with(Position { x: 0, y: 0 })
            .with(Size { w: 10, h: 10 })
            .with(RenderController)
            .build();

        for (i, tile) in map.iter().enumerate() {
            let _map_tile = w.create_now()
                .with(ImmovableController)
                .with(Size { w: 1, h: 1 })
                .with(Position { x: i as i32 % map_width, y: i as i32 / map_width, })
                .with(Tile { c: tile.clone() })
                .build();
        }

        // resources can be installed, these are nothing fancy, but allow you
        // to pass data to systems and follow the same sync strategy as the
        // component storage does.
        w.add_resource(Command(String::new()));

        // Planner is used to run systems on the specified world with a specified number of threads
        (specs::Planner::<()>::new(w, 4))
    };
    loop {
        planner.run_custom(|arg| {
            let (mut positions, velocities) = arg.fetch(|w| {
                (w.write::<Position>(), w.read::<Velocity>())
            });

            for (mut p, v) in (&mut positions, &velocities).iter() {
                p.x += v.dx;
                p.y += v.dy;
            }
        });

        planner.wait();

        // render view
        planner.run_custom(|arg| {
            let (tiles, positions) = arg.fetch(|w| {
                (w.read::<Tile>(), w.read::<Position>())
            });
            let mut output = Vec::with_capacity(100);

            for (tile, position) in (&tiles, &positions).iter() {
                println!("{:?} {:?}", tile, position);
                output.insert((position.y * 10 + position.x) as usize, tile.c);
            }
            //for x in 0..m.width {
            //    for y in 0..m.height {
            //        if x == p.x as i32 && y == p.y as i32 {
            //        } else {
            //            print!("{}", world_map.map[i * width + j]);
            //        }
            //        if j == width - 1 {
            //            println!("");
            //        }
            //    }
            //}
            let output: String = output.into_iter().collect();
            println!("{}", output);
        });

        planner.wait();

        // set view
        planner.run_custom(|arg| {
            let (mut positions, players, views, map_objects, sizes, entities) = arg.fetch(|w| {
                (w.write::<Position>(), w.read::<PlayerController>(), w.read::<RenderController>(),
                w.read::<ImmovableController>(), w.read::<Size>(),
                w.entities())
            });

            let mut pos = (None, None);
            for (_, position) in (&players, &positions).iter() {
                pos.0 = Some(position.x);
                pos.1 = Some(position.y);
                break;
            }

            if let (Some(x), Some(y)) = pos {
                for (_, size, entity) in (&views, &sizes, &entities).iter() {
                    let view_pos = positions.get_mut(entity)
                        .expect("render controller expect position component");
                    view_pos.x = x - (size.w as i32 / 2);
                    view_pos.y = y - (size.h as i32 / 2);
                }
            }
        });

        // get input
        planner.run_custom(|arg| {
            let mut cmd = arg.fetch(|w| {
                (w.write_resource::<Command>())
            });
            let mut input = String::new();
            if let Ok(_) = io::stdin().read_line(&mut input) {
                cmd.0 = input;
            }
        });

        planner.wait();

        // process input
        planner.run_custom(|arg| {
            let (mut velocities, players, cmds, entities) = arg.fetch(|w| {
                (w.write::<Velocity>(), w.read::<PlayerController>(),
                 w.read_resource::<Command>(), w.entities())
            });
            let mut commands: Vec<&str> = cmds.0.split_whitespace()
                .rev()
                .collect();

            for (_, entity) in (&players, &entities).iter() {
                let velocity = velocities.get_mut(entity)
                    .expect("player controller expect velocity");
                let mut dx = 0;
                let mut dy = 0;
                while let Some(word) = commands.pop() {
                    match word {
                        "left" | "l" => {
                            if let Some(val) = commands.pop() {
                                dx -= val.parse::<i32>().unwrap_or(1);
                            } else {
                                dx -= 1;
                            }
                        }
                        "right" | "r" => {
                            if let Some(val) = commands.pop() {
                                dx += val.parse::<i32>().unwrap_or(1);
                            } else {
                                dx += 1;
                            }
                        }
                        "up" | "u" => {
                            if let Some(val) = commands.pop() {
                                dy -= val.parse::<i32>().unwrap_or(1);
                            } else {
                                dy -= 1;
                            }
                        }
                        "down" | "d" => {
                            if let Some(val) = commands.pop() {
                                dy += val.parse::<i32>().unwrap_or(1);
                            } else {
                                dy += 1;
                            }
                        }
                        _ => {}
                    }
                }
                velocity.dx += dx;
                velocity.dy += dy;
                println!("{:?}", velocity);
            }
        });

        planner.wait();
    }
}
<commit_msg>Fix initialize output with spaces then with tiles.<commit_after>extern crate specs;

use specs::Join;
use std::io::prelude::*;
use std::io;
use std::io::BufReader;
use std::fs::File;

static MAP: &'static str = include_str!("../map");

#[derive(Copy, Clone, Debug, PartialEq)]
struct Tile {
    c: char,
}

impl specs::Component for Tile {
    type Storage = specs::VecStorage<Tile>;
}

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

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

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

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

impl specs::Component for PlayerController {
    type Storage = specs::VecStorage<PlayerController >;
}

impl specs::Component for NonPlayerController {
    type Storage = specs::VecStorage<NonPlayerController >;
}

impl specs::Component for RenderController {
    type Storage = specs::VecStorage<RenderController >;
}

impl specs::Component for ImmovableController {
    type Storage = specs::VecStorage<ImmovableController>;
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Position {
    x: i32,
    y: i32,
}

impl specs::Component for Position {
    type Storage = specs::VecStorage<Position>;
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Velocity {
    dx: i32,
    dy: i32,
}

impl specs::Component for Velocity {
    type Storage = specs::VecStorage<Velocity>;
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Size {
    w: u32,
    h: u32,
}

impl specs::Component for Size {
    type Storage = specs::VecStorage<Size>;
}

#[derive(Clone, Debug, PartialEq)]
struct WorldMap(Vec<char>);

#[derive(Clone, Debug)]
struct Command(String);

//#[cfg(not(feature="parallel"))]
//fn main() {
//}
//
//#[cfg(feature="parallel")]
fn main() {
    let map_width = 10;
    let height = 10;
    let mut lines: Vec<&str> = MAP.lines().collect();
    let map_settings = lines.remove(0);
    for word in map_settings.split_whitespace() {
    }
    let map: Vec<char> = lines.iter().flat_map(|line| line.chars()).collect();

    let mut planner = {
        let mut w = specs::World::new();
        w.register::<Size>();
        w.register::<Tile>();
        w.register::<Position>();
        w.register::<Velocity>();
        w.register::<PlayerController>();
        w.register::<NonPlayerController>();
        w.register::<RenderController>();
        w.register::<ImmovableController>();

        // Entities
        let _player = w.create_now()
            .with(Tile { c: '😀' })
            .with(Velocity { dx: 0, dy: 0 })
            .with(Position { x: 0, y: 0 })
            .with(PlayerController)
            .with(Size { w: 1, h: 1 })
            .build();

        let _view = w.create_now()
            .with(Position { x: 0, y: 0 })
            .with(Size { w: 10, h: 10 })
            .with(RenderController)
            .build();

        for (i, tile) in map.iter().enumerate() {
            let _map_tile = w.create_now()
                .with(ImmovableController)
                .with(Size { w: 1, h: 1 })
                .with(Position { x: i as i32 % map_width, y: i as i32 / map_width, })
                .with(Tile { c: tile.clone() })
                .build();
        }

        // resources can be installed, these are nothing fancy, but allow you
        // to pass data to systems and follow the same sync strategy as the
        // component storage does.
        w.add_resource(Command(String::new()));

        // Planner is used to run systems on the specified world with a specified number of threads
        (specs::Planner::<()>::new(w, 4))
    };
    loop {
        planner.run_custom(|arg| {
            let (mut positions, velocities) = arg.fetch(|w| {
                (w.write::<Position>(), w.read::<Velocity>())
            });

            for (mut p, v) in (&mut positions, &velocities).iter() {
                p.x += v.dx;
                p.y += v.dy;
            }
        });

        planner.wait();

        // render view
        planner.run_custom(|arg| {
            let (tiles, positions) = arg.fetch(|w| {
                (w.read::<Tile>(), w.read::<Position>())
            });
            let mut output = vec![' ';100];

            for (tile, position) in (&tiles, &positions).iter() {
                println!("{:?} {:?}", tile, position);
                output.insert((position.y * 10 + position.x) as usize, tile.c);
            }
            //for x in 0..m.width {
            //    for y in 0..m.height {
            //        if x == p.x as i32 && y == p.y as i32 {
            //        } else {
            //            print!("{}", world_map.map[i * width + j]);
            //        }
            //        if j == width - 1 {
            //            println!("");
            //        }
            //    }
            //}
            let output: String = output.into_iter().collect();
            println!("{}", output);
        });

        planner.wait();

        // set view
        planner.run_custom(|arg| {
            let (mut positions, players, views, map_objects, sizes, entities) = arg.fetch(|w| {
                (w.write::<Position>(), w.read::<PlayerController>(), w.read::<RenderController>(),
                w.read::<ImmovableController>(), w.read::<Size>(),
                w.entities())
            });

            let mut pos = (None, None);
            for (_, position) in (&players, &positions).iter() {
                pos.0 = Some(position.x);
                pos.1 = Some(position.y);
                break;
            }

            if let (Some(x), Some(y)) = pos {
                for (_, size, entity) in (&views, &sizes, &entities).iter() {
                    let view_pos = positions.get_mut(entity)
                        .expect("render controller expect position component");
                    view_pos.x = x - (size.w as i32 / 2);
                    view_pos.y = y - (size.h as i32 / 2);
                }
            }
        });

        // get input
        planner.run_custom(|arg| {
            let mut cmd = arg.fetch(|w| {
                (w.write_resource::<Command>())
            });
            let mut input = String::new();
            if let Ok(_) = io::stdin().read_line(&mut input) {
                cmd.0 = input;
            }
        });

        planner.wait();

        // process input
        planner.run_custom(|arg| {
            let (mut velocities, players, cmds, entities) = arg.fetch(|w| {
                (w.write::<Velocity>(), w.read::<PlayerController>(),
                 w.read_resource::<Command>(), w.entities())
            });
            let mut commands: Vec<&str> = cmds.0.split_whitespace()
                .rev()
                .collect();

            for (_, entity) in (&players, &entities).iter() {
                let velocity = velocities.get_mut(entity)
                    .expect("player controller expect velocity");
                let mut dx = 0;
                let mut dy = 0;
                while let Some(word) = commands.pop() {
                    match word {
                        "left" | "l" => {
                            if let Some(val) = commands.pop() {
                                dx -= val.parse::<i32>().unwrap_or(1);
                            } else {
                                dx -= 1;
                            }
                        }
                        "right" | "r" => {
                            if let Some(val) = commands.pop() {
                                dx += val.parse::<i32>().unwrap_or(1);
                            } else {
                                dx += 1;
                            }
                        }
                        "up" | "u" => {
                            if let Some(val) = commands.pop() {
                                dy -= val.parse::<i32>().unwrap_or(1);
                            } else {
                                dy -= 1;
                            }
                        }
                        "down" | "d" => {
                            if let Some(val) = commands.pop() {
                                dy += val.parse::<i32>().unwrap_or(1);
                            } else {
                                dy += 1;
                            }
                        }
                        _ => {}
                    }
                }
                velocity.dx += dx;
                velocity.dy += dy;
                println!("{:?}", velocity);
            }
        });

        planner.wait();
    }
}
<|endoftext|>


<commit_before>extern crate postgres;
extern crate rand;
extern crate time;
extern crate csv;

use postgres::{Connection, SslMode};
use std::env::{var_os};
use time::{precise_time_ns, now_utc};
use rand::{random};
use std::cmp::{min};
use std::thread::{sleep_ms};
use std::io::{stdout,Write};
use csv::Writer;

struct Reservoir {
    r: Vec<(f64, (f64, f64))>,
    size: usize
}

fn weight () -> f64 {
    random::<f64>().powf((1.0f64 / ((precise_time_ns()/1000) as f64).log(10.0)))
}

fn update (r: Reservoir, value: (f64, f64)) -> Reservoir {
    let new_pair = (weight(), value);
    let mut new_v = Vec::new();
    let mut cont = true;
    let mut idx = 0;
    while cont {
        if new_v.len() == r.size {
            cont = false
        } else if idx == r.r.len() {
            new_v.push(new_pair);
            cont = false
        } else if r.r[idx].0 < new_pair.0 {
            new_v.push(r.r[idx])
        } else {
            new_v.push(new_pair);
            for ii in idx..min(r.size, r.r.len()) {
                new_v.push(r.r[ii])
            }
            cont = false;
        }
        idx = idx + 1
    }
    Reservoir {r: new_v, size: r.size}
}

fn values (r: &Reservoir) -> Vec<(f64, f64)> {
    let mut new_v = Vec::new();
    for i in 0..r.r.len() {
        new_v.push(r.r[i].1)
    }
    new_v
}

fn pair_wise_mean (v: &Vec<(f64, f64)>) -> (f64, f64) {
    let mut xsum = 0.0f64;
    let mut ysum = 0.0f64;
    for i in 0..v.len() {
        xsum = xsum + v[i].0;
        ysum = ysum + v[i].1;
    }
    (xsum/(v.len() as f64), ysum/(v.len() as f64))
}

fn least_squares_line_of_best_fit (pairs: Vec<(f64, f64)>) -> (f64, f64) {
    let ref p = pairs;
    let means = pair_wise_mean(p);
    let mut t = 0f64;
    let mut u = 0f64;
    let l = p.len();
    for i in 0..l {
        t = ((pairs[i].0 - means.0) * (pairs[i].1 - means.1)) + t;
        u = ((pairs[i].0 - means.0) * (pairs[i].0 - means.0)) + u;
    }
    let m = t/u;
    let b = means.1 - (m * means.0);
    (m, b)
}

fn x_intercept (m: f64, b: f64) -> f64 {
    (0f64 - b) / m
}

fn main () {
    match (var_os("PG_URL"), var_os("PG_QUERY"))  {
        (Some(url), Some(query)) => {
            let conn = Connection::connect(url.to_str().unwrap(), &SslMode::None).unwrap();
            let stmt = conn.prepare(query.to_str().unwrap()).unwrap();
            let mut r = Reservoir{r:Vec::new(), size: 10};
            let mut i = 0;
            loop {
                let mut w = Writer::from_memory().delimiter(b'\t');
                if (i % 20) == 0 {
                    w.encode(("time", "recent-x", "recent-y", "x-intercept", "y-intercept", "m")).ok().unwrap();
                }
                for row in stmt.query(&[]).unwrap() {
                    let x = row.get(0);
                    let y = row.get(1);
                    r = update(r, (x,y));
                    if i > 2 {
                        let (m, b) = least_squares_line_of_best_fit(values(&r));
                        w.encode((now_utc().rfc3339().to_string(), x, y, x_intercept(m, b), b, m)).ok().unwrap();
                    }
                };
                stdout().write_all(w.as_bytes()).ok().unwrap();
                sleep_ms(1000*60);
                i = i + 1
            }
        },
        _ => println!("Be sure to define PG_URL and PG_QUERY")
    }
}
<commit_msg>weighted Reservoir sampling is actually bad for my use case (eta estimation), switch to a simple ring buffer<commit_after>extern crate postgres;
extern crate rand;
extern crate time;
extern crate csv;

use postgres::{Connection, SslMode};
use std::env::{var_os};
use time::{precise_time_ns, now_utc};
use rand::{random};
use std::cmp::{min};
use std::thread::{sleep_ms};
use std::io::{stdout,Write};
use csv::Writer;

struct RingBuffer {
    d: Vec<(f64, f64)>,
    size: usize,
    pos:usize
}

fn update (r: RingBuffer, value: (f64, f64)) -> RingBuffer {
    let p = r.pos % r.size;
    if r.d.len() > p {
        let mut d = r.d.clone();
        d[p] = value;
        let d1 = d;
        RingBuffer{d:d1,size:r.size,pos:p+1}
    } else {
        let mut d = r.d.clone();
        d.push(value);
        let d1 = d;
        RingBuffer{d:d1,size:r.size,pos:p+1}
    }
}

fn pair_wise_mean (v: &Vec<(f64, f64)>) -> (f64, f64) {
    let mut xsum = 0.0f64;
    let mut ysum = 0.0f64;
    for i in 0..v.len() {
        xsum = xsum + v[i].0;
        ysum = ysum + v[i].1;
    }
    (xsum/(v.len() as f64), ysum/(v.len() as f64))
}

fn least_squares_line_of_best_fit (pairs: Vec<(f64, f64)>) -> (f64, f64) {
    let ref p = pairs;
    let means = pair_wise_mean(p);
    let mut t = 0f64;
    let mut u = 0f64;
    let l = p.len();
    for i in 0..l {
        t = ((pairs[i].0 - means.0) * (pairs[i].1 - means.1)) + t;
        u = ((pairs[i].0 - means.0) * (pairs[i].0 - means.0)) + u;
    }
    let m = t/u;
    let b = means.1 - (m * means.0);
    (m, b)
}

fn x_intercept (m: f64, b: f64) -> f64 {
    (0f64 - b) / m
}

fn main () {
    match (var_os("PG_URL"), var_os("PG_QUERY"))  {
        (Some(url), Some(query)) => {
            let conn = Connection::connect(url.to_str().unwrap(), &SslMode::None).unwrap();
            let stmt = conn.prepare(query.to_str().unwrap()).unwrap();
            let mut r = RingBuffer{d:Vec::new(), size: 100, pos: 0};
            let mut i = 0;
            loop {
                let mut w = Writer::from_memory().delimiter(b'\t');
                if (i % 20) == 0 {
                    w.encode(("time", "recent-x", "recent-y", "x-intercept", "y-intercept", "m")).ok().unwrap();
                }
                for row in stmt.query(&[]).unwrap() {
                    let x = row.get(0);
                    let y = row.get(1);
                    r = update(r, (x,y));
                    if i > 2 {
                        let (m, b) = least_squares_line_of_best_fit(r.d.clone());
                        w.encode((now_utc().rfc3339().to_string(), x, y, x_intercept(m, b), b, m)).ok().unwrap();
                    }
                };
                stdout().write_all(w.as_bytes()).ok().unwrap();
                sleep_ms(1000*60);
                i = i + 1
            }
        },
        _ => println!("Be sure to define PG_URL and PG_QUERY")
    }
}
<|endoftext|>


<commit_before>// Don't show a console window when running on Windows.
#![windows_subsystem = "windows"]

extern crate rand;
extern crate euclid;
extern crate glium;
extern crate scancode;
extern crate vitral;
extern crate calx_grid;
#[macro_use]
extern crate calx_alg;
extern crate world;
extern crate display;

pub mod game_loop;

use euclid::{Point2D, Rect, Size2D};
use game_loop::GameLoop;
use glium::{DisplayBuild, glutin};
use vitral::Context;
use world::World;

pub fn main() {
    // Construct display and Vitral context.
    let glium = glutin::WindowBuilder::new().build_glium().unwrap();

    let screen_area = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(640.0f32, 360.0f32));
    let mut backend = display::Backend::new(
        &glium,
        screen_area.size.width as u32,
        screen_area.size.height as u32,
    );

    let seed = 1;

    let mut game = GameLoop::new(World::new(seed));

    loop {
        backend.begin_frame();
        game.draw(&mut backend, &screen_area);
        if !backend.update(&glium) {
            return;
        }
    }
}
<commit_msg>Randomize starter world<commit_after>// Don't show a console window when running on Windows.
#![windows_subsystem = "windows"]

extern crate rand;
extern crate euclid;
extern crate glium;
extern crate scancode;
extern crate vitral;
extern crate calx_grid;
#[macro_use]
extern crate calx_alg;
extern crate world;
extern crate display;

pub mod game_loop;

use euclid::{Point2D, Rect, Size2D};
use game_loop::GameLoop;
use glium::{DisplayBuild, glutin};
use vitral::Context;
use world::World;
use rand::Rng;

pub fn main() {
    // Construct display and Vitral context.
    let glium = glutin::WindowBuilder::new().build_glium().unwrap();

    let screen_area = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(640.0f32, 360.0f32));
    let mut backend = display::Backend::new(
        &glium,
        screen_area.size.width as u32,
        screen_area.size.height as u32,
    );

    let seed = rand::thread_rng().gen();
    // Print out the seed in case worldgen has a bug and we want to debug stuff with the same seed.
    println!("Seed: {}", seed);

    let mut game = GameLoop::new(World::new(seed));

    loop {
        backend.begin_frame();
        game.draw(&mut backend, &screen_area);
        if !backend.update(&glium) {
            return;
        }
    }
}
<|endoftext|>


<commit_before>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

use std::fs::{self, PathExt};
use std::path::Path;
use std::str::FromStr;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool,
    level: u32
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.to_str().unwrap());
        let mut s = String::new();

        match std::io::stdin().read_line(&mut s) {
            Ok(_) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s == "y" || tmp_s == "yes" {
                    return true;
                } else if tmp_s == "n" || tmp_s == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path, level: u32) {
    let m = ::std::fs::metadata(&entry).unwrap();

    if m.is_file() || m.is_dir() {
        if m.is_dir() {
            if (options.recursive || entry.to_str().unwrap() == ".") &&
                (options.level == 0 || level <= options.level) {
                match fs::read_dir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.to_str().unwrap());
                        }
                        for tmp in res {
                            match tmp {
                                Ok(current) => {
                                    start_clean(options, &current.path(), level + 1);
                                },
                                Err(e) => println!("Error: {:?}", e)
                            };
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.to_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.file_name() {
                Some(s) => {
                    match s.to_str() {
                        Some(ss) => if ss.ends_with("~") {
                            if !options.confirmation || ask_confirmation(&Path::new(s)) {
                                match fs::remove_file(entry) {
                                    Ok(_) => {
                                        if options.verbose {
                                            println!("\x1b[32;1m{} deleted\x1b[0m", entry.to_str().unwrap());
                                        }
                                    }
                                    Err(e) => {
                                        println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                                    }
                                }
                            }
                        },
                        _ => {}
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.to_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.to_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r          : recursive mode");
    println!("    -v          : verbose mode");
    println!("    -i          : prompt before every removal");
    println!("    -l=[number] : Add a level for recursive mode");
    println!("--help : print this help");
}

fn main() {
    let mut args = Vec::new();

    for argument in std::env::args() {
        args.push(argument);
    }
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false, level: 0};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = tmp.to_owned();

            tmp_arg.remove(0);
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if &*tmp == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        'l' => {
                            if tmp.len() < 4 || &tmp[0..3] != "-l=" {
                                println!("The \"-l\" option has to be used like this:");
                                println!("clean -r -l=2");
                                return;
                            }
                            options.level = match u32::from_str(&tmp[3..]) {
                                Ok(u) => u,
                                Err(_) => {
                                    println!("Please enter a valid number!");
                                    return;
                                }
                            };
                            println!("Level is set to {}", options.level);
                            break;
                        }
                        _ => {
                            println!("Unknown option: '{}', to have the options list, please launch with '-h' option", *character as char);
                            return;
                        }
                    }
                }
            }/* else {
                files.push(Path::new(tmp));
            }*/
        } else {
            files.push(Path::new(tmp));
        }
    }
    if files.len() == 0 {
        files.push(Path::new("."));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp, 0);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<commit_msg>Update to last rustc version<commit_after>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

use std::fs;
use std::path::Path;
use std::str::FromStr;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool,
    level: u32
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.to_str().unwrap());
        let mut s = String::new();

        match std::io::stdin().read_line(&mut s) {
            Ok(_) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s == "y" || tmp_s == "yes" {
                    return true;
                } else if tmp_s == "n" || tmp_s == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path, level: u32) {
    let m = ::std::fs::metadata(&entry).unwrap();

    if m.is_file() || m.is_dir() {
        if m.is_dir() {
            if (options.recursive || entry.to_str().unwrap() == ".") &&
                (options.level == 0 || level <= options.level) {
                match fs::read_dir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.to_str().unwrap());
                        }
                        for tmp in res {
                            match tmp {
                                Ok(current) => {
                                    start_clean(options, &current.path(), level + 1);
                                },
                                Err(e) => println!("Error: {:?}", e)
                            };
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.to_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.file_name() {
                Some(s) => {
                    match s.to_str() {
                        Some(ss) => if ss.ends_with("~") {
                            if !options.confirmation || ask_confirmation(&Path::new(s)) {
                                match fs::remove_file(entry) {
                                    Ok(_) => {
                                        if options.verbose {
                                            println!("\x1b[32;1m{} deleted\x1b[0m", entry.to_str().unwrap());
                                        }
                                    }
                                    Err(e) => {
                                        println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.to_str().unwrap(), e);
                                    }
                                }
                            }
                        },
                        _ => {}
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.to_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.to_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r          : recursive mode");
    println!("    -v          : verbose mode");
    println!("    -i          : prompt before every removal");
    println!("    -l=[number] : Add a level for recursive mode");
    println!("--help : print this help");
}

fn main() {
    let mut args = Vec::new();

    for argument in std::env::args() {
        args.push(argument);
    }
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false, level: 0};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = tmp.to_owned();

            tmp_arg.remove(0);
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if &*tmp == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        'l' => {
                            if tmp.len() < 4 || &tmp[0..3] != "-l=" {
                                println!("The \"-l\" option has to be used like this:");
                                println!("clean -r -l=2");
                                return;
                            }
                            options.level = match u32::from_str(&tmp[3..]) {
                                Ok(u) => u,
                                Err(_) => {
                                    println!("Please enter a valid number!");
                                    return;
                                }
                            };
                            println!("Level is set to {}", options.level);
                            break;
                        }
                        _ => {
                            println!("Unknown option: '{}', to have the options list, please launch with '-h' option", *character as char);
                            return;
                        }
                    }
                }
            }/* else {
                files.push(Path::new(tmp));
            }*/
        } else {
            files.push(Path::new(tmp));
        }
    }
    if files.len() == 0 {
        files.push(Path::new("."));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp, 0);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<|endoftext|>


<commit_before>// Copyright 2017 Zachary Bush.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(unused_allocation, unused_attributes, unused_features, unused_import_braces,
        unused_parens, unused_must_use, stable_features, bad_style, unused)]

#[macro_use]
extern crate chan;
extern crate clap;
extern crate git2;
extern crate log4rs;
#[macro_use]
extern crate log;
extern crate num;
extern crate prompt_buffer;
extern crate term;
extern crate time;
extern crate unix_socket;

use prompt_buffer::{PromptBuffer, PromptThread, ShellType};

use std::collections::HashMap;
use std::fs;
use std::io::{Read, Write};

use time::Duration;
use log4rs::config;
use log4rs::append::file::FileAppender;
use log4rs::encode::pattern::PatternEncoder;

use unix_socket::{UnixListener, UnixStream};
use std::env;
use std::path::{Path, PathBuf};
use std::net::Shutdown;
use std::thread;
use chan::Receiver;
use std::os::unix::fs::MetadataExt;
use std::process::Command;
use clap::{App, Arg, ArgGroup};

mod git;
mod due_date;

fn get_prompt(shell: ShellType) -> PromptBuffer {
    let mut buf = PromptBuffer::new(shell);
    buf.add_plugin(due_date::DueDatePlugin::new());
    buf.add_plugin(git::GitPlugin::new());

    buf
}

fn exe_changed() -> i64 {
    match env::current_exe() {
        Ok(exe_path) => match fs::metadata(exe_path) {
            Ok(m) => m.mtime(),
            Err(_) => 0i64,
        },
        Err(_) => 0i64,
    }
}

macro_rules! sock_try {
    ($x:expr) => {
        match $x {
            Ok(v) => v,
            Err(_) => continue
        }
    };
}

#[allow(dead_code)]
enum RunMode {
    Daemon,
    Main,
    Test,
}

#[allow(dead_code)]
fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .after_help(env!("CARGO_PKG_HOMEPAGE"))
        .arg(
            Arg::with_name("daemon")
                .short("d")
                .long("daemon")
                .help("Run the daemon"),
        )
        .arg(
            Arg::with_name("bash")
                .short("b")
                .long("bash")
                .help("Get output for bash"),
        )
        .arg(
            Arg::with_name("zsh")
                .short("z")
                .long("zsh")
                .help("Get output for zsh"),
        )
        .group(
            ArgGroup::with_name("mode")
                .args(&["daemon", "bash", "zsh"])
                .required(true),
        )
        .get_matches();
    let daemon = matches.is_present("daemon");
    let shell = if matches.is_present("bash") {
        ShellType::Bash
    } else {
        ShellType::Zsh
    };
    run(
        if daemon {
            RunMode::Daemon
        } else {
            RunMode::Main
        },
        shell,
    )
}

fn do_daemon(socket_path: &Path) {
    let main_log = FileAppender::builder()
        .encoder(Box::new(PatternEncoder::new("{h({f:>30.30}: {m}{n})}")))
        .build("/var/log/megaprompt/current.out")
        .expect("Unable to create file appender");

    let config = config::Config::builder()
        .appender(config::Appender::builder().build("main", Box::new(main_log)))
        .build(
            config::Root::builder()
                .appender("main")
                .build(log::LogLevelFilter::Trace),
        )
        .expect("Unable to create logger config");

    log4rs::init_config(config).expect("Unable to init logger");

    let last_modified = exe_changed();
    let mut threads: HashMap<(PathBuf, ShellType), PromptThread> = HashMap::new();

    if socket_path.exists() {
        fs::remove_file(socket_path).expect("Unable to remove socket file");
    }

    let stream = match UnixListener::bind(socket_path) {
        Err(_) => unreachable!("unable to bind to socket"),
        Ok(stream) => stream,
    };

    info!("BIND");

    for connection in stream.incoming() {
        let mut c = match connection {
            Ok(c) => c,
            Err(_) => continue,
        };

        let mut output = String::new();
        let _ = sock_try!(c.read_to_string(&mut output));
        let (output, shell) = if output.starts_with("!2 ") {
            let parts = output.split(" ").collect::<Vec<_>>();
            let output = PathBuf::from(&parts[1]);
            let shell = match parts[2] {
                "Bash" => ShellType::Bash,
                "Zsh" => ShellType::Zsh,
                _ => ShellType::Bash,
            };
            (output, shell)
        } else {
            (PathBuf::from(&output), ShellType::Bash)
        };
        info!(
            "Preparing to respond to for {} [{:?}]",
            output.display(),
            shell
        );

        let keys: Vec<(PathBuf, ShellType)> = threads.keys().cloned().collect();
        for entry in &keys {
            if !threads
                .get_mut(entry)
                .expect("thread not there!")
                .check_is_alive()
            {
                info!("- Remove thread {}", entry.0.display());
                let _ = threads.remove(entry);
            }
        }

        if !threads.contains_key(&(output.clone(), shell)) {
            info!("+ Add thread {}", output.display());
            let t = sock_try!(PromptThread::new(output.clone(), &|| get_prompt(shell)));
            let _ = threads.insert((output.clone(), shell), t);
        }

        for &(ref path, ref shell) in threads.keys() {
            info!("* Active thread {} [{:?}]", path.display(), shell);
        }

        let thr = threads
            .get_mut(&(output, shell))
            .expect("Thread not present");

        info!("Getting response from thread");
        sock_try!(write!(c, "{}", sock_try!(thr.get(&|| get_prompt(shell)))));

        info!("");

        if last_modified != exe_changed() {
            warn!("Found newer version of myself. Quitting.");
            sock_try!(write!(c, "♻  "));
            return;
        }
    }
}

fn oneshot_timer(dur: Duration) -> Receiver<()> {
    let (tx, rx) = chan::async();

    thread::spawn(move || {
        thread::sleep(::std::time::Duration::from_millis(
            dur.num_milliseconds() as u64,
        ));
        let _ = tx.send(());
    });

    rx
}

fn read_with_timeout(mut stream: UnixStream, dur: Duration) -> Result<String, String> {
    let (tx, rx) = chan::sync(0);

    let _ = thread::spawn(move || {
        let mut ret = String::new();
        stream
            .read_to_string(&mut ret)
            .expect("Unable to read from string");
        let _ = tx.send(ret);
    });

    let timeout = oneshot_timer(dur);

    #[allow(unused_mut)]
    {
        chan_select! {
            rx.recv() ->resp => return Ok(resp.expect("There is no response!")),
            timeout.recv() => return Err("Timeout".to_owned())
        }
    }
}

fn do_main(socket_path: &Path, shell: ShellType) {
    let _ = Command::new("megapromptd").arg("start").output();

    let mut stream = match UnixStream::connect(socket_path) {
        Err(_) => {
            println!("Can't connect");
            get_prompt(shell).print();
            return;
        }
        Ok(stream) => stream,
    };

    write!(
        &mut stream,
        "!2 {} {:?}",
        env::current_dir()
            .expect("There is no current dir")
            .display(),
        shell
    ).expect("Unable to print current directory");
    stream
        .shutdown(Shutdown::Write)
        .expect("Cannot shutdown stream");

    match read_with_timeout(stream, Duration::milliseconds(100)) {
        Ok(s) => println!("{}", s),
        Err(_) => {
            println!("Response too slow");
            get_prompt(shell).print_fast();
            return;
        }
    }
}

fn run(mode: RunMode, shell: ShellType) {
    let socket_path = Path::new("/tmp/megaprompt-socket");

    match mode {
        RunMode::Daemon => do_daemon(socket_path),
        RunMode::Main => do_main(socket_path, shell),
        RunMode::Test => {}
    }
}

#[test]
fn test_main_does_not_error() {
    run(RunMode::Test);
}
<commit_msg>Fix test<commit_after>// Copyright 2017 Zachary Bush.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(unused_allocation, unused_attributes, unused_features, unused_import_braces,
        unused_parens, unused_must_use, stable_features, bad_style, unused)]

#[macro_use]
extern crate chan;
extern crate clap;
extern crate git2;
extern crate log4rs;
#[macro_use]
extern crate log;
extern crate num;
extern crate prompt_buffer;
extern crate term;
extern crate time;
extern crate unix_socket;

use prompt_buffer::{PromptBuffer, PromptThread, ShellType};

use std::collections::HashMap;
use std::fs;
use std::io::{Read, Write};

use time::Duration;
use log4rs::config;
use log4rs::append::file::FileAppender;
use log4rs::encode::pattern::PatternEncoder;

use unix_socket::{UnixListener, UnixStream};
use std::env;
use std::path::{Path, PathBuf};
use std::net::Shutdown;
use std::thread;
use chan::Receiver;
use std::os::unix::fs::MetadataExt;
use std::process::Command;
use clap::{App, Arg, ArgGroup};

mod git;
mod due_date;

fn get_prompt(shell: ShellType) -> PromptBuffer {
    let mut buf = PromptBuffer::new(shell);
    buf.add_plugin(due_date::DueDatePlugin::new());
    buf.add_plugin(git::GitPlugin::new());

    buf
}

fn exe_changed() -> i64 {
    match env::current_exe() {
        Ok(exe_path) => match fs::metadata(exe_path) {
            Ok(m) => m.mtime(),
            Err(_) => 0i64,
        },
        Err(_) => 0i64,
    }
}

macro_rules! sock_try {
    ($x:expr) => {
        match $x {
            Ok(v) => v,
            Err(_) => continue
        }
    };
}

#[allow(dead_code)]
enum RunMode {
    Daemon,
    Main,
    Test,
}

#[allow(dead_code)]
fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .after_help(env!("CARGO_PKG_HOMEPAGE"))
        .arg(
            Arg::with_name("daemon")
                .short("d")
                .long("daemon")
                .help("Run the daemon"),
        )
        .arg(
            Arg::with_name("bash")
                .short("b")
                .long("bash")
                .help("Get output for bash"),
        )
        .arg(
            Arg::with_name("zsh")
                .short("z")
                .long("zsh")
                .help("Get output for zsh"),
        )
        .group(
            ArgGroup::with_name("mode")
                .args(&["daemon", "bash", "zsh"])
                .required(true),
        )
        .get_matches();
    let daemon = matches.is_present("daemon");
    let shell = if matches.is_present("bash") {
        ShellType::Bash
    } else {
        ShellType::Zsh
    };
    run(
        if daemon {
            RunMode::Daemon
        } else {
            RunMode::Main
        },
        shell,
    )
}

fn do_daemon(socket_path: &Path) {
    let main_log = FileAppender::builder()
        .encoder(Box::new(PatternEncoder::new("{h({f:>30.30}: {m}{n})}")))
        .build("/var/log/megaprompt/current.out")
        .expect("Unable to create file appender");

    let config = config::Config::builder()
        .appender(config::Appender::builder().build("main", Box::new(main_log)))
        .build(
            config::Root::builder()
                .appender("main")
                .build(log::LogLevelFilter::Trace),
        )
        .expect("Unable to create logger config");

    log4rs::init_config(config).expect("Unable to init logger");

    let last_modified = exe_changed();
    let mut threads: HashMap<(PathBuf, ShellType), PromptThread> = HashMap::new();

    if socket_path.exists() {
        fs::remove_file(socket_path).expect("Unable to remove socket file");
    }

    let stream = match UnixListener::bind(socket_path) {
        Err(_) => unreachable!("unable to bind to socket"),
        Ok(stream) => stream,
    };

    info!("BIND");

    for connection in stream.incoming() {
        let mut c = match connection {
            Ok(c) => c,
            Err(_) => continue,
        };

        let mut output = String::new();
        let _ = sock_try!(c.read_to_string(&mut output));
        let (output, shell) = if output.starts_with("!2 ") {
            let parts = output.split(" ").collect::<Vec<_>>();
            let output = PathBuf::from(&parts[1]);
            let shell = match parts[2] {
                "Bash" => ShellType::Bash,
                "Zsh" => ShellType::Zsh,
                _ => ShellType::Bash,
            };
            (output, shell)
        } else {
            (PathBuf::from(&output), ShellType::Bash)
        };
        info!(
            "Preparing to respond to for {} [{:?}]",
            output.display(),
            shell
        );

        let keys: Vec<(PathBuf, ShellType)> = threads.keys().cloned().collect();
        for entry in &keys {
            if !threads
                .get_mut(entry)
                .expect("thread not there!")
                .check_is_alive()
            {
                info!("- Remove thread {}", entry.0.display());
                let _ = threads.remove(entry);
            }
        }

        if !threads.contains_key(&(output.clone(), shell)) {
            info!("+ Add thread {}", output.display());
            let t = sock_try!(PromptThread::new(output.clone(), &|| get_prompt(shell)));
            let _ = threads.insert((output.clone(), shell), t);
        }

        for &(ref path, ref shell) in threads.keys() {
            info!("* Active thread {} [{:?}]", path.display(), shell);
        }

        let thr = threads
            .get_mut(&(output, shell))
            .expect("Thread not present");

        info!("Getting response from thread");
        sock_try!(write!(c, "{}", sock_try!(thr.get(&|| get_prompt(shell)))));

        info!("");

        if last_modified != exe_changed() {
            warn!("Found newer version of myself. Quitting.");
            sock_try!(write!(c, "♻  "));
            return;
        }
    }
}

fn oneshot_timer(dur: Duration) -> Receiver<()> {
    let (tx, rx) = chan::async();

    thread::spawn(move || {
        thread::sleep(::std::time::Duration::from_millis(
            dur.num_milliseconds() as u64,
        ));
        let _ = tx.send(());
    });

    rx
}

fn read_with_timeout(mut stream: UnixStream, dur: Duration) -> Result<String, String> {
    let (tx, rx) = chan::sync(0);

    let _ = thread::spawn(move || {
        let mut ret = String::new();
        stream
            .read_to_string(&mut ret)
            .expect("Unable to read from string");
        let _ = tx.send(ret);
    });

    let timeout = oneshot_timer(dur);

    #[allow(unused_mut)]
    {
        chan_select! {
            rx.recv() ->resp => return Ok(resp.expect("There is no response!")),
            timeout.recv() => return Err("Timeout".to_owned())
        }
    }
}

fn do_main(socket_path: &Path, shell: ShellType) {
    let _ = Command::new("megapromptd").arg("start").output();

    let mut stream = match UnixStream::connect(socket_path) {
        Err(_) => {
            println!("Can't connect");
            get_prompt(shell).print();
            return;
        }
        Ok(stream) => stream,
    };

    write!(
        &mut stream,
        "!2 {} {:?}",
        env::current_dir()
            .expect("There is no current dir")
            .display(),
        shell
    ).expect("Unable to print current directory");
    stream
        .shutdown(Shutdown::Write)
        .expect("Cannot shutdown stream");

    match read_with_timeout(stream, Duration::milliseconds(100)) {
        Ok(s) => println!("{}", s),
        Err(_) => {
            println!("Response too slow");
            get_prompt(shell).print_fast();
            return;
        }
    }
}

fn run(mode: RunMode, shell: ShellType) {
    let socket_path = Path::new("/tmp/megaprompt-socket");

    match mode {
        RunMode::Daemon => do_daemon(socket_path),
        RunMode::Main => do_main(socket_path, shell),
        RunMode::Test => {}
    }
}

#[test]
fn test_main_does_not_error() {
    run(RunMode::Test, ShellType::Bash);
}
<|endoftext|>


<commit_before>// Playing with paths.

extern crate rsure;
extern crate env_logger;
extern crate regex;

#[macro_use]
extern crate log;

#[macro_use]
extern crate clap;

use clap::{App, AppSettings, Arg, SubCommand};

use std::collections::BTreeMap;
use std::path::Path;

use rsure::{show_tree, Progress, SureHash, TreeCompare, stdout_visitor, parse_store, StoreTags, Version};

mod bkcmd;

// For now, just use the crate's error type.
pub use rsure::Result;

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

    let matches = App::new("rsure")
        .version(crate_version!())
        .setting(AppSettings::GlobalVersion)
        .arg(Arg::with_name("file")
             .short("f")
             .long("file")
             .takes_value(true)
             .help("Base of file name, default 2sure, will get .dat.gz appended"))
        .arg(Arg::with_name("dir")
             .short("d")
             .long("dir")
             .takes_value(true)
             .help("Directory to scan, defaults to \".\""))
        .arg(Arg::with_name("tag")
             .long("tag")
             .takes_value(true)
             .multiple(true)
             .help("key=value to associate with scan"))
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("scan")
                    .about("Scan a directory for the first time"))
        .subcommand(SubCommand::with_name("update")
                    .about("Update the scan using the dat file"))
        .subcommand(SubCommand::with_name("check")
                    .about("Compare the directory with the dat file"))
        .subcommand(SubCommand::with_name("signoff")
                    .about("Compare the dat file with the bak file"))
        .subcommand(SubCommand::with_name("show")
                    .about("Pretty print the dat file"))
        .subcommand(SubCommand::with_name("bknew")
                    .about("Create a new bitkeeper-based sure store")
                    .arg(Arg::with_name("dir")
                         .required(true)
                         .help("Directory to create bk-based store")))
        .subcommand(SubCommand::with_name("bkimport")
                    .about("Import a tree of surefiles into a bk store")
                    .arg(Arg::with_name("src")
                         .long("src")
                         .takes_value(true)
                         .required(true))
                    .arg(Arg::with_name("dest")
                         .long("dest")
                         .takes_value(true)
                         .required(true)))
        .get_matches();

    let dir = matches.value_of("dir").unwrap_or(".");

    let file = matches.value_of("file").unwrap_or("2sure.dat.gz");
    let store = parse_store(file).unwrap();

    let tags = decode_tags(matches.values_of("tag"));
    println!("tag: {:?}", tags);

    match matches.subcommand() {
        ("scan", Some(_)) => {
            rsure::update(&dir, &*store, false, &tags).unwrap();
        },
        ("update", Some(_)) => {
            rsure::update(&dir, &*store, true, &tags).unwrap();
        },
        ("check", Some(_)) => {
            let old_tree = store.load(Version::Latest).unwrap();
            let mut new_tree = rsure::scan_fs(&dir).unwrap();
            let estimate = new_tree.hash_estimate();
            let pdir = &Path::new(dir);
            let mut progress = Progress::new(estimate.files, estimate.bytes);
            new_tree.hash_update(pdir, &mut progress);
            progress.flush();
            info!("check {:?}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, pdir);
        },
        ("signoff", Some(_)) => {
            let old_tree = store.load(Version::Prior).unwrap();
            let new_tree = store.load(Version::Latest).unwrap();
            println!("signoff {}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, &Path::new(dir));
        },
        ("show", Some(_)) => {
            println!("show {}", file);
            show_tree(&Path::new(&file)).unwrap();
        },
        ("bknew", Some(sub)) => {
            let bkdir = sub.value_of("dir").unwrap();
            bkcmd::new(bkdir).unwrap();
        },
        ("bkimport", Some(sub)) => {
            let src = sub.value_of("src").unwrap();
            let dest = sub.value_of("dest").unwrap();
            bkcmd::import(src, dest).unwrap();
        },
        _ => {
            panic!("Unsupported command.");
        }
    }
}

/// Decode the command-line tags.  Tags should be of the form key=value, and multiple can be
/// specified, terminated by the command.  It is also possible to specify --tag multiple times.
fn decode_tags<'a, I>(tags: Option<I>) -> StoreTags
    where I: Iterator<Item=&'a str>
{
    match tags {
        None => BTreeMap::new(),
        Some(tags) => tags.map(|x| decode_tag(x)).collect(),
    }
}

fn decode_tag<'a>(tag: &'a str) -> (String, String) {
    let fields: Vec<_> = tag.splitn(2, '=').collect();
    if fields.len() != 2 {
        panic!("Tag must be key=value");
    }
    (fields[0].to_string(), fields[1].to_string())
}
<commit_msg>Remove 'tag' debugging line<commit_after>// Playing with paths.

extern crate rsure;
extern crate env_logger;
extern crate regex;

#[macro_use]
extern crate log;

#[macro_use]
extern crate clap;

use clap::{App, AppSettings, Arg, SubCommand};

use std::collections::BTreeMap;
use std::path::Path;

use rsure::{show_tree, Progress, SureHash, TreeCompare, stdout_visitor, parse_store, StoreTags, Version};

mod bkcmd;

// For now, just use the crate's error type.
pub use rsure::Result;

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

    let matches = App::new("rsure")
        .version(crate_version!())
        .setting(AppSettings::GlobalVersion)
        .arg(Arg::with_name("file")
             .short("f")
             .long("file")
             .takes_value(true)
             .help("Base of file name, default 2sure, will get .dat.gz appended"))
        .arg(Arg::with_name("dir")
             .short("d")
             .long("dir")
             .takes_value(true)
             .help("Directory to scan, defaults to \".\""))
        .arg(Arg::with_name("tag")
             .long("tag")
             .takes_value(true)
             .multiple(true)
             .help("key=value to associate with scan"))
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("scan")
                    .about("Scan a directory for the first time"))
        .subcommand(SubCommand::with_name("update")
                    .about("Update the scan using the dat file"))
        .subcommand(SubCommand::with_name("check")
                    .about("Compare the directory with the dat file"))
        .subcommand(SubCommand::with_name("signoff")
                    .about("Compare the dat file with the bak file"))
        .subcommand(SubCommand::with_name("show")
                    .about("Pretty print the dat file"))
        .subcommand(SubCommand::with_name("bknew")
                    .about("Create a new bitkeeper-based sure store")
                    .arg(Arg::with_name("dir")
                         .required(true)
                         .help("Directory to create bk-based store")))
        .subcommand(SubCommand::with_name("bkimport")
                    .about("Import a tree of surefiles into a bk store")
                    .arg(Arg::with_name("src")
                         .long("src")
                         .takes_value(true)
                         .required(true))
                    .arg(Arg::with_name("dest")
                         .long("dest")
                         .takes_value(true)
                         .required(true)))
        .get_matches();

    let dir = matches.value_of("dir").unwrap_or(".");

    let file = matches.value_of("file").unwrap_or("2sure.dat.gz");
    let store = parse_store(file).unwrap();

    let tags = decode_tags(matches.values_of("tag"));

    match matches.subcommand() {
        ("scan", Some(_)) => {
            rsure::update(&dir, &*store, false, &tags).unwrap();
        },
        ("update", Some(_)) => {
            rsure::update(&dir, &*store, true, &tags).unwrap();
        },
        ("check", Some(_)) => {
            let old_tree = store.load(Version::Latest).unwrap();
            let mut new_tree = rsure::scan_fs(&dir).unwrap();
            let estimate = new_tree.hash_estimate();
            let pdir = &Path::new(dir);
            let mut progress = Progress::new(estimate.files, estimate.bytes);
            new_tree.hash_update(pdir, &mut progress);
            progress.flush();
            info!("check {:?}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, pdir);
        },
        ("signoff", Some(_)) => {
            let old_tree = store.load(Version::Prior).unwrap();
            let new_tree = store.load(Version::Latest).unwrap();
            println!("signoff {}", file);
            new_tree.compare_from(&mut stdout_visitor(), &old_tree, &Path::new(dir));
        },
        ("show", Some(_)) => {
            println!("show {}", file);
            show_tree(&Path::new(&file)).unwrap();
        },
        ("bknew", Some(sub)) => {
            let bkdir = sub.value_of("dir").unwrap();
            bkcmd::new(bkdir).unwrap();
        },
        ("bkimport", Some(sub)) => {
            let src = sub.value_of("src").unwrap();
            let dest = sub.value_of("dest").unwrap();
            bkcmd::import(src, dest).unwrap();
        },
        _ => {
            panic!("Unsupported command.");
        }
    }
}

/// Decode the command-line tags.  Tags should be of the form key=value, and multiple can be
/// specified, terminated by the command.  It is also possible to specify --tag multiple times.
fn decode_tags<'a, I>(tags: Option<I>) -> StoreTags
    where I: Iterator<Item=&'a str>
{
    match tags {
        None => BTreeMap::new(),
        Some(tags) => tags.map(|x| decode_tag(x)).collect(),
    }
}

fn decode_tag<'a>(tag: &'a str) -> (String, String) {
    let fields: Vec<_> = tag.splitn(2, '=').collect();
    if fields.len() != 2 {
        panic!("Tag must be key=value");
    }
    (fields[0].to_string(), fields[1].to_string())
}
<|endoftext|>


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

extern crate bip_bencode;
extern crate bip_metainfo;
extern crate bip_utracker;
extern crate chrono;
extern crate hyper;
extern crate pretty_env_logger;
extern crate rustyline;
extern crate url;

use bip_bencode::Bencode;
use bip_metainfo::MetainfoFile;
use bip_utracker::contact::CompactPeersV4;
use chrono::{TimeZone, UTC};
use hyper::Client;
use hyper::header::Connection;
use nom::IResult;
use rustyline::Editor;
use rustyline::error::ReadlineError;
use url::Url;

use std::fs::File;
use std::io::prelude::*;
use std::str;
use std::string::String;

const HISTORY_FILE: &'static str = ".rustyline.history";

/// Print general information about the torrent.
fn print_metainfo_overview(bytes: &[u8]) {
    let metainfo = MetainfoFile::from_bytes(bytes).unwrap();
    let info = metainfo.info();
    let info_hash_hex = metainfo.info_hash()
        .as_ref()
        .iter()
        .map(|b| format!("{:02X}", b))
        .fold(String::new(), |mut acc, nex| {
            acc.push_str(&nex);
            acc
        });
    let utc_creation_date = metainfo.creation_date().map(|c| UTC.timestamp(c, 0));

    println!("\n\n-----------------------------Metainfo File Overview-----------------------------");

    println!("InfoHash: {}", info_hash_hex);
    println!("Main Tracker: {:?}", metainfo.main_tracker());
    println!("Comment: {:?}", metainfo.comment());
    println!("Creator: {:?}", metainfo.created_by());
    println!("Creation Date: {:?}", utc_creation_date);

    println!("Directory: {:?}", info.directory());
    println!("Piece Length: {:?}", info.piece_length());
    println!("Number Of Pieces: {}", info.pieces().count());
    println!("Number Of Files: {}", info.files().count());
    println!("Total File Size: {}",
             info.files().fold(0, |acc, nex| acc + nex.length()));
}

fn connect_to_tracker(metainfo_file: MetainfoFile, peer_id: &str, port: u16) -> Result<(), String> {
    debug!("connecting to tracker: {:?}", metainfo_file.main_tracker());
    let info_hash = metainfo_file.info_hash();
    let info_hash_str = unsafe { str::from_utf8_unchecked(info_hash.as_ref()) };
    let total_len = metainfo_file.info().files().fold(0, |acc, nex| acc + nex.length());

    let mut url = Url::parse(metainfo_file.main_tracker().unwrap()).unwrap();
    url.query_pairs_mut()
        .append_pair("info_hash", &info_hash_str)
        .append_pair("peer_id", "-TR2920-utffmgat89lc")
        .append_pair("port", &(port.to_string()))
        .append_pair("uploaded", "0")
        .append_pair("downloaded", "0")
        .append_pair("left", &(total_len.to_string()))
        .append_pair("compact", "1")
        .append_pair("event", "started")
        .append_pair("supportcrypto", "0");
    debug!("URL {:?}", url);

    let client = Client::new();
    let mut res = client.get(url).header(Connection::close()).send().unwrap();
    let mut buffer = Vec::new();
    res.read_to_end(&mut buffer);
    debug!("Resp {:?}", res);
    let bencode = Bencode::decode(&buffer).unwrap();
    debug!("{:?}", bencode);
    // debug!("{:?}", Bencode::decode((bencode.dict().unwrap().lookup("peers")
    //               .unwrap().bytes().unwrap())).unwrap());

    Ok(())
}

fn main() {
    pretty_env_logger::init();

    let mut rl = Editor::<()>::new();
    if rl.load_history(HISTORY_FILE).is_err() {
        info!("No previous history!");
    }
    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(cmd) => {
                rl.add_history_entry(&cmd);

                let cmd = cmd.trim().split(' ').collect::<Vec<&str>>();

                match cmd[0] {
                    "parse" => {
                        if cmd.len() != 2 {
                            error!("usage: parse <torrent file>");
                        } else {
                            let path = cmd[1];
                            debug!("MetainfoFile: {:?}", path);

                            match File::open(path) {
                                Ok(mut f) => {
                                    let mut bytes: Vec<u8> = Vec::new();
                                    f.read_to_end(&mut bytes).unwrap();
                                    print_metainfo_overview(&bytes);
                                    connect_to_tracker(MetainfoFile::from_bytes(&bytes).unwrap(),
                                                       "myid",
                                                       6882 /* .unwrap()
                                                             * .main_tracker() */);
                                }
                                Err(e) => error!("{:?}", e),
                            }
                        }
                    }
                    _ => {}
                }
            }
            Err(ReadlineError::Interrupted) => {
                break;
            }
            Err(ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                error!("Error: {:?}", err);
                break;
            }
        }
    }
    rl.save_history(HISTORY_FILE).unwrap();
}
<commit_msg>Iterate over tracker returned peers<commit_after>#[macro_use]
extern crate log;
#[macro_use]
extern crate nom;

extern crate bip_bencode;
extern crate bip_metainfo;
extern crate bip_utracker;
extern crate chrono;
extern crate hyper;
extern crate pretty_env_logger;
extern crate rustyline;
extern crate url;

use bip_bencode::Bencode;
use bip_metainfo::MetainfoFile;
use bip_utracker::contact::CompactPeersV4;
use chrono::{TimeZone, UTC};
use hyper::Client;
use hyper::header::Connection;
use nom::IResult;
use rustyline::Editor;
use rustyline::error::ReadlineError;
use url::Url;

use std::fs::File;
use std::io::prelude::*;
use std::str;
use std::string::String;

const HISTORY_FILE: &'static str = ".rustyline.history";

/// Print general information about the torrent.
fn print_metainfo_overview(bytes: &[u8]) {
    let metainfo = MetainfoFile::from_bytes(bytes).unwrap();
    let info = metainfo.info();
    let info_hash_hex = metainfo.info_hash()
        .as_ref()
        .iter()
        .map(|b| format!("{:02X}", b))
        .fold(String::new(), |mut acc, nex| {
            acc.push_str(&nex);
            acc
        });
    let utc_creation_date = metainfo.creation_date().map(|c| UTC.timestamp(c, 0));

    println!("\n\n-----------------------------Metainfo File Overview-----------------------------");

    println!("InfoHash: {}", info_hash_hex);
    println!("Main Tracker: {:?}", metainfo.main_tracker());
    println!("Comment: {:?}", metainfo.comment());
    println!("Creator: {:?}", metainfo.created_by());
    println!("Creation Date: {:?}", utc_creation_date);

    println!("Directory: {:?}", info.directory());
    println!("Piece Length: {:?}", info.piece_length());
    println!("Number Of Pieces: {}", info.pieces().count());
    println!("Number Of Files: {}", info.files().count());
    println!("Total File Size: {}",
             info.files().fold(0, |acc, nex| acc + nex.length()));
}

fn connect_to_tracker(metainfo_file: MetainfoFile, peer_id: &str, port: u16) -> Result<(), String> {
    debug!("connecting to tracker: {:?}", metainfo_file.main_tracker());
    let info_hash = metainfo_file.info_hash();
    let info_hash_str = unsafe { str::from_utf8_unchecked(info_hash.as_ref()) };
    let total_len = metainfo_file.info().files().fold(0, |acc, nex| acc + nex.length());

    let mut url = Url::parse(metainfo_file.main_tracker().unwrap()).unwrap();
    url.query_pairs_mut()
        .append_pair("info_hash", &info_hash_str)
        .append_pair("peer_id", "-TR2920-utffmgat89lc")
        .append_pair("port", &(port.to_string()))
        .append_pair("uploaded", "0")
        .append_pair("downloaded", "0")
        .append_pair("left", &(total_len.to_string()))
        .append_pair("compact", "1")
        .append_pair("event", "started")
        .append_pair("supportcrypto", "0");
    debug!("URL {:?}", url);

    let client = Client::new();
    let mut res = client.get(url).header(Connection::close()).send().unwrap();
    let mut buffer = Vec::new();
    res.read_to_end(&mut buffer);
    debug!("Resp {:?}", res);
    let bencode = Bencode::decode(&buffer).unwrap();
    debug!("{:?}", bencode);
    let (_, peers) = CompactPeersV4::from_bytes(bencode.dict()
            .unwrap()
            .lookup("peers")
            .unwrap()
            .bytes()
            .unwrap())
        .unwrap();
    debug!("{:?}", peers);
    for peer in peers.iter() {
        debug!("{:?}", peer);
    }

    Ok(())
}

fn main() {
    pretty_env_logger::init();

    let mut rl = Editor::<()>::new();
    if rl.load_history(HISTORY_FILE).is_err() {
        info!("No previous history!");
    }
    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(cmd) => {
                rl.add_history_entry(&cmd);

                let cmd = cmd.trim().split(' ').collect::<Vec<&str>>();

                match cmd[0] {
                    "parse" => {
                        if cmd.len() != 2 {
                            error!("usage: parse <torrent file>");
                        } else {
                            let path = cmd[1];
                            debug!("MetainfoFile: {:?}", path);

                            match File::open(path) {
                                Ok(mut f) => {
                                    let mut bytes: Vec<u8> = Vec::new();
                                    f.read_to_end(&mut bytes).unwrap();
                                    print_metainfo_overview(&bytes);
                                    connect_to_tracker(MetainfoFile::from_bytes(&bytes).unwrap(),
                                                       "myid",
                                                       6882 /* .unwrap()
                                                             * .main_tracker() */);
                                }
                                Err(e) => error!("{:?}", e),
                            }
                        }
                    }
                    _ => {}
                }
            }
            Err(ReadlineError::Interrupted) => {
                break;
            }
            Err(ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                error!("Error: {:?}", err);
                break;
            }
        }
    }
    rl.save_history(HISTORY_FILE).unwrap();
}
<|endoftext|>