<commit_before>use std::thread;
use std::time::Duration;
use time::precise_time_ns;

use bootstrap::{Action, Context, Key, Keyboard, Mouse, MouseButton, MouseMove, Scroll, Window};
use camera::{Camera, Freefly};
use transform::Translation;

/// All common stuff goes here.
pub struct App {
  /// Some kind of epoch start the application started at.
  start_time: u64,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Last known cursor position.
  last_cursor: [f64; 2],
  /// Is the mouse’s left button pressed down?
  left_down: bool,
  /// Is the mouse’s right button pressed down?
  right_down: bool,
}

impl App {
  pub fn init(kbd: Keyboard, mouse: Mouse, cursor: MouseMove, scroll: Scroll, window: Window) -> Self {
    App {
      start_time: precise_time_ns(),
      kbd: kbd,
      mouse: mouse,
      cursor: cursor,
      scroll: scroll,
      window: window,
      last_cursor: [0., 0.],
      left_down: false,
      right_down: false,
    }
  }

  pub fn time(&self) -> f32 {
    (precise_time_ns() - self.start_time) as f32 * 1e-9
  }

  pub fn handle_events(&mut self, camera: &mut Camera<Freefly>) -> bool {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if action == Action::Release && key == Key::Escape{
        return false;
      } else {
        match key {
          Key::W => camera.mv(Translation::new(0., 0., 1.)),
          Key::S => camera.mv(Translation::new(0., 0., -1.)),
          Key::A => camera.mv(Translation::new(1., 0., 0.)),
          Key::D => camera.mv(Translation::new(-1., 0., 0.)),
          Key::Q => camera.mv(Translation::new(0., -1., 0.)),
          Key::E => camera.mv(Translation::new(0., 1., 0.)),
          _ => {}
        }
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      match (button, action) {
        (MouseButton::Button1, Action::Press) => {
          self.left_down = true;
        },
        (MouseButton::Button1, Action::Release) => {
          self.left_down = false;
        },
        (MouseButton::Button2, Action::Press) => {
          self.right_down = true;
        },
        (MouseButton::Button2, Action::Release) => {
          self.right_down = false;
        },
        _ => {}
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if self.left_down {
        let (dx, dy) = (xy[0] - self.last_cursor[0], xy[1] - self.last_cursor[1]);
        camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
      } else if self.right_down {
        let (dx, _) = (xy[0] - self.last_cursor[0], xy[1] - self.last_cursor[1]);
        camera.look_around(Translation::new(0., 0., dx as f32));
      }

      self.last_cursor = xy;
    }

    true
  }

  pub fn step<R>(&mut self, fps: Option<u32>, mut draw_frame: R) -> bool where R: FnMut(f32) {
    let loop_start_time = precise_time_ns();

    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);

    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps {
      let fps = fps as f32;
      let elapsed_time_ms = ((precise_time_ns() - loop_start_time) as f64 * 1e-6) as i64;
      let sleep_time_ms = (1. / fps * 1e3) as i64 - elapsed_time_ms;

      if sleep_time_ms > 0 {
        thread::sleep(Duration::from_millis(sleep_time_ms as u64));
      }
    }

    true
  }
}
<commit_msg>Simplified App and make it more flexible about events.<commit_after>use std::thread;
use std::time::Duration;
use time::precise_time_ns;

use bootstrap::{Context, Keyboard, Mouse, MouseMove, Scroll, Window};
pub use bootstrap::{Action, Key, MouseButton};
use camera::{Camera, Freefly};
use transform::Translation;

#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

/// Class of keyboard handlers.
pub trait KeyboardHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool;
}

impl KeyboardHandler for Unhandled {
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
}

/// Class of mouse button handlers.
pub trait MouseButtonHandler {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool;
}

impl MouseButtonHandler for Unhandled {
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
}

/// Class of mouse move handlers.
pub trait CursorHandler {
  fn on_mouse_move(&mut self, cursor_pos: [f64; 2]) -> bool;
}

impl CursorHandler for Unhandled {
  fn on_mouse_move(&mut self, _: [f64; 2]) -> bool { true }
}

/// Class of scroll handlers.
pub trait ScrollHandler {
  fn on_scroll(&mut self, scroll_dir: [f64; 2]) -> bool;
}

impl ScrollHandler for Unhandled {
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

/// All common stuff goes here.
pub struct App {
  /// Some kind of epoch start the application started at.
  start_time: u64,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
}

impl App {
  pub fn init(kbd: Keyboard, mouse: Mouse, cursor: MouseMove, scroll: Scroll, window: Window) -> Self {
    App {
      start_time: precise_time_ns(),
      kbd: kbd,
      mouse: mouse,
      cursor: cursor,
      scroll: scroll,
      window: window
    }
  }

  pub fn time(&self) -> f32 {
    (precise_time_ns() - self.start_time) as f32 * 1e-9
  }

  pub fn dispatch_events<K, MB, MM, S>(&self,
                                       keyboard_handler: &mut K,
                                       mouse_button_handler: &mut MB,
                                       cursor_handler: &mut MM,
                                       scroll_handler: &mut S) -> bool
      where K: KeyboardHandler,
            MB: MouseButtonHandler,
            MM: CursorHandler,
            S: ScrollHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !keyboard_handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !mouse_button_handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !cursor_handler.on_mouse_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !scroll_handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  pub fn step<R>(&mut self, fps: Option<u32>, mut draw_frame: R) -> bool where R: FnMut(f32) {
    let loop_start_time = precise_time_ns();

    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);

    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps {
      let fps = fps as f32;
      let elapsed_time_ms = ((precise_time_ns() - loop_start_time) as f64 * 1e-6) as i64;
      let sleep_time_ms = (1. / fps * 1e3) as i64 - elapsed_time_ms;

      if sleep_time_ms > 0 {
        thread::sleep(Duration::from_millis(sleep_time_ms as u64));
      }
    }

    true
  }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, WriteBytesExt};
use libc::consts::os::posix88::*;
use libc::funcs::posix88::mman::mmap;
use libc::funcs::posix88::mman::munmap;
use libc::types::common::c95::c_void;
use libc::types::os::arch::c95::size_t;
use std::ptr;
use std::mem;

pub struct Assembler {
    code: Vec<u8>
}

impl Assembler {
    pub fn new() -> Assembler {
        Assembler { code: Vec::new() }
    }

    pub fn movq(&mut self, dest: Reg64, src: u64) {
        self.code.push(0x48);
        self.code.push(0xB8);
        self.code.write_u64::<LittleEndian>(src).unwrap();
    }

    pub fn nop(&mut self) {
        self.code.push(0x90);
    }

    pub fn ret(&mut self) {
        self.code.push(0xC3);
    }
}

enum Reg64 {
    rax
}

static CODE : [u8;8] = [ 0x48u8, 0x89, 0xf8, 0x48, 0x83, 0xc0, 0x04, 0xc3 ];

pub struct JitFunction {
    pub size: size_t,
    pub call: extern fn (u64) -> u64
}

impl JitFunction {
    pub fn new(code: &[u8]) -> JitFunction {
        let size = code.len() as u64;

        unsafe {
            let fct = mmap(0 as *mut c_void, size, PROT_READ | PROT_WRITE | PROT_EXEC,
                MAP_PRIVATE | MAP_ANON, -1, 0);

            if fct == MAP_FAILED {
                panic!("mmap failed");
            }

            ptr::copy_nonoverlapping(code.as_ptr() as *const c_void, fct, code.len());

            JitFunction {
                size: size,
                call: mem::transmute(fct)
            }
        }
    }
}

impl Drop for JitFunction {
    fn drop(&mut self) {
        unsafe {
            munmap(mem::transmute(self.call), self.size);
        }
    }
}

#[test]
fn test_create_function() {
    let fct = JitFunction::new(&CODE);

    assert_eq!(5, (fct.call)(1));
}
<commit_msg>remove type for literal<commit_after>use byteorder::{LittleEndian, WriteBytesExt};
use libc::consts::os::posix88::*;
use libc::funcs::posix88::mman::mmap;
use libc::funcs::posix88::mman::munmap;
use libc::types::common::c95::c_void;
use libc::types::os::arch::c95::size_t;
use std::ptr;
use std::mem;

pub struct Assembler {
    code: Vec<u8>
}

impl Assembler {
    pub fn new() -> Assembler {
        Assembler { code: Vec::new() }
    }

    pub fn movq(&mut self, dest: Reg64, src: u64) {
        self.code.push(0x48);
        self.code.push(0xB8);
        self.code.write_u64::<LittleEndian>(src).unwrap();
    }

    pub fn nop(&mut self) {
        self.code.push(0x90);
    }

    pub fn ret(&mut self) {
        self.code.push(0xC3);
    }
}

enum Reg64 {
    rax
}

static CODE : [u8;8] = [ 0x48, 0x89, 0xf8, 0x48, 0x83, 0xc0, 0x04, 0xc3 ];

pub struct JitFunction {
    pub size: size_t,
    pub call: extern fn (u64) -> u64
}

impl JitFunction {
    pub fn new(code: &[u8]) -> JitFunction {
        let size = code.len() as u64;

        unsafe {
            let fct = mmap(0 as *mut c_void, size, PROT_READ | PROT_WRITE | PROT_EXEC,
                MAP_PRIVATE | MAP_ANON, -1, 0);

            if fct == MAP_FAILED {
                panic!("mmap failed");
            }

            ptr::copy_nonoverlapping(code.as_ptr() as *const c_void, fct, code.len());

            JitFunction {
                size: size,
                call: mem::transmute(fct)
            }
        }
    }
}

impl Drop for JitFunction {
    fn drop(&mut self) {
        unsafe {
            munmap(mem::transmute(self.call), self.size);
        }
    }
}

#[test]
fn test_create_function() {
    let fct = JitFunction::new(&CODE);

    assert_eq!(5, (fct.call)(1));
}
<|endoftext|>


<commit_before>
#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    EmptyList(EmptyListNode),
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::EmptyList(ref ast) => ast.print(),
        }
    }
}

macro_rules! is_type {
    ($func_name:ident, $type_name:ident) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            match *self {
                ExprAst::$type_name(_) => true,
                _ => false
            }
        }})
}

is_type!(is_char, Char)
is_type!(is_pair, Pair)
is_type!(is_int, Int)
is_type!(is_empty, EmptyList)
is_type!(is_symbol, Symbol)
is_type!(is_string, Str)
is_type!(is_proc, Proc)
is_type!(is_bool, Bool)

#[allow(dead_code)]
impl ExprAst {
    pub fn is_true(&self) -> bool {
        return self.as_bool();
    }

    pub fn is_false(&self) -> bool {
        return !self.as_bool();
    }

    pub fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    pub fn as_int(&self) -> int {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    pub fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    pub fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }

    pub fn car(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[0].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn cdr(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[1].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn is_last(&self) -> bool {
        assert!(self.is_pair());
        return self.cdr().is_empty();
    }

    pub fn is_self(&self) -> bool {
        match *self {
            ExprAst::Bool(_) => true,
            ExprAst::Int(_) => true,
            ExprAst::Char(_) => true,
            ExprAst::Str(_) => true,
            _ => false
        }
    }

    pub fn is_quote(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("quote")));
    }

    pub fn is_assign(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("set!")));
    }

    pub fn is_def(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("def")));
    }

    pub fn is_and(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("and")));
    }

    pub fn is_or(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("or")));
    }

    pub fn is_if(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("if")));
    }

    pub fn is_lambda(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("lambda")));
    }

    pub fn is_cond(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("cond")));
    }

    pub fn is_let(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("let")));
    }

    pub fn is_begin(&self) -> bool {
        return self.is_tagged(ExprAst::Symbol(SymbolNode::new("begin")));
    }

    pub fn def_var(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().car()
        } else {
            self.cdr().car().car()
        }
    }

    pub fn def_val(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().cdr().car()
        } else {
            //proc
            ExprAst::Symbol(SymbolNode::new("OK"))
        }
    }

    fn is_tagged(&self, tag: ExprAst) -> bool {
        if self.is_pair() {
            let car = self.car();
            return car.is_symbol() && car == tag;
        }
        return false;
    }
}

#[deriving(Clone, PartialEq, Eq)]
pub struct IntNode {
    value: int
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: int) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: &str) -> StrNode {
        StrNode{ value: val.to_string()}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pair: Vec<ExprAst>,
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(car: ExprAst, cdr: ExprAst) -> PairNode {
        PairNode {
            pair: vec![car, cdr]
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.pair[0].print();
        self.pair[1].print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: &str) -> SymbolNode {
        SymbolNode {
            value: val.to_string()
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

//FIXME, empty struct?
#[deriving(Clone, PartialEq)]
pub struct EmptyListNode {
    pub value: String
}

#[allow(dead_code)]
impl EmptyListNode {
    pub fn new() -> EmptyListNode {
        EmptyListNode {
            value: "EmptyListNode".to_string()
        }
    }
}

impl Ast for EmptyListNode{
    fn print(&self) {
        println!("EmptyListNode");
    }
}

#[deriving(Clone)]
struct ProcFunc(fn(ExprAst) -> ExprAst);

impl PartialEq for ProcFunc {
    fn eq(&self, o: &ProcFunc) -> bool {
        let _o: *const() = unsafe { ::std::mem::transmute(o)};
        let _s: *const() = unsafe { ::std::mem::transmute(self)};
        _s == _o
    }
    fn ne(&self, o: &ProcFunc) -> bool {
        !self.eq(o)
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    value: String,
    func: ProcFunc
}

impl ProcNode {
    pub fn new(obj: fn(ExprAst)-> ExprAst) -> ProcNode {
        ProcNode {
            value: "proc".to_string(),
            func: ProcFunc(obj)
        }
    }
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
    assert!(int_node.is_self());
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_str() == "hello");
    assert!(str_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3");
    assert!(int_node.is_self());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello"));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(int_node, str_node));
    let car_node = pair_node.car();
    let cdr_node = pair_node.cdr();
    assert!(car_node.as_int() == 3);
    assert!(cdr_node.as_str() == "hello");
    assert!(!pair_node.is_self());
}

#[test]
fn test_ast_symbol() {
    let sym_node = ExprAst::Symbol(SymbolNode::new("sym"));
    assert!(sym_node.is_symbol());
    assert!(!sym_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_pair_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    let car_node = int_node.car();
    assert!(car_node.as_int() == 3);
}

#[test]
fn test_ast_emptylist() {
    let empty_node = ExprAst::EmptyList(EmptyListNode::new());
    assert!(empty_node.is_empty());
    assert!(!empty_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_emptylist_fail() {
    let empty_node = ExprAst::Int(IntNode::new(3));
    assert!(empty_node.is_empty());
    assert!(empty_node.is_quote());
}
<commit_msg>add testcase for macro_rules<commit_after>
#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    EmptyList(EmptyListNode),
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::EmptyList(ref ast) => ast.print(),
        }
    }
}

macro_rules! is_ast_type {
    ($func_name:ident, $type_name:ident) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            match *self {
                ExprAst::$type_name(_) => true,
                _ => false
            }
        }})
}

is_ast_type!(is_char, Char)
is_ast_type!(is_pair, Pair)
is_ast_type!(is_int, Int)
is_ast_type!(is_empty, EmptyList)
is_ast_type!(is_symbol, Symbol)
is_ast_type!(is_string, Str)
is_ast_type!(is_proc, Proc)
is_ast_type!(is_bool, Bool)

macro_rules! is_type {
    ($func_name:ident, $type_str:expr) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            return self.is_tagged(ExprAst::Symbol(SymbolNode::new($type_str)));
        }
    })
}

is_type!(is_quote, "quote")
is_type!(is_def, "def")
is_type!(is_and, "and")
is_type!(is_or, "or")
is_type!(is_if, "if")
is_type!(is_assign, "set!")
is_type!(is_lambda, "lambda")
is_type!(is_cond, "cond")
is_type!(is_let, "let")
is_type!(is_begin, "begin")

#[allow(dead_code)]
impl ExprAst {
    pub fn is_true(&self) -> bool {
        return self.as_bool();
    }

    pub fn is_false(&self) -> bool {
        return !self.as_bool();
    }

    pub fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    pub fn as_int(&self) -> int {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    pub fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    pub fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }

    pub fn car(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[0].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn cdr(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[1].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn is_last(&self) -> bool {
        assert!(self.is_pair());
        return self.cdr().is_empty();
    }

    pub fn is_self(&self) -> bool {
        match *self {
            ExprAst::Bool(_) => true,
            ExprAst::Int(_) => true,
            ExprAst::Char(_) => true,
            ExprAst::Str(_) => true,
            _ => false
        }
    }

    pub fn def_var(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().car()
        } else {
            self.cdr().car().car()
        }
    }

    pub fn def_val(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().cdr().car()
        } else {
            //proc
            ExprAst::Symbol(SymbolNode::new("OK"))
        }
    }

    fn is_tagged(&self, tag: ExprAst) -> bool {
        if self.is_pair() {
            let car = self.car();
            return car.is_symbol() && car == tag;
        }
        return false;
    }
}

#[deriving(Clone, PartialEq, Eq)]
pub struct IntNode {
    value: int
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: int) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: &str) -> StrNode {
        StrNode{ value: val.to_string()}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pair: Vec<ExprAst>,
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(car: ExprAst, cdr: ExprAst) -> PairNode {
        PairNode {
            pair: vec![car, cdr]
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.pair[0].print();
        self.pair[1].print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: &str) -> SymbolNode {
        SymbolNode {
            value: val.to_string()
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

//FIXME, empty struct?
#[deriving(Clone, PartialEq)]
pub struct EmptyListNode {
    pub value: String
}

#[allow(dead_code)]
impl EmptyListNode {
    pub fn new() -> EmptyListNode {
        EmptyListNode {
            value: "EmptyListNode".to_string()
        }
    }
}

impl Ast for EmptyListNode{
    fn print(&self) {
        println!("EmptyListNode");
    }
}

#[deriving(Clone)]
struct ProcFunc(fn(ExprAst) -> ExprAst);

impl PartialEq for ProcFunc {
    fn eq(&self, o: &ProcFunc) -> bool {
        let _o: *const() = unsafe { ::std::mem::transmute(o)};
        let _s: *const() = unsafe { ::std::mem::transmute(self)};
        _s == _o
    }
    fn ne(&self, o: &ProcFunc) -> bool {
        !self.eq(o)
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    value: String,
    func: ProcFunc
}

impl ProcNode {
    pub fn new(obj: fn(ExprAst)-> ExprAst) -> ProcNode {
        ProcNode {
            value: "proc".to_string(),
            func: ProcFunc(obj)
        }
    }
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
    assert!(int_node.is_self());
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_str() == "hello");
    assert!(str_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3");
    assert!(int_node.is_self());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello"));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(int_node, str_node));
    let car_node = pair_node.car();
    let cdr_node = pair_node.cdr();
    assert!(car_node.as_int() == 3);
    assert!(cdr_node.as_str() == "hello");
    assert!(!pair_node.is_self());
}

#[test]
fn test_ast_symbol() {
    let sym_node = ExprAst::Symbol(SymbolNode::new("sym"));
    assert!(sym_node.is_symbol());
    assert!(!sym_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_pair_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    let car_node = int_node.car();
    assert!(car_node.as_int() == 3);
}

#[test]
fn test_ast_emptylist() {
    let empty_node = ExprAst::EmptyList(EmptyListNode::new());
    assert!(empty_node.is_empty());
    assert!(!empty_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_emptylist_fail() {
    let empty_node = ExprAst::Int(IntNode::new(3));
    assert!(empty_node.is_empty());
    assert!(empty_node.is_quote());
}

#[test]
fn test_ast_is_set() {

    macro_rules! test_case {
        ($str_name:expr) => {
            {let node = ExprAst::Pair(PairNode::new(
                ExprAst::Symbol(SymbolNode::new($str_name)),
                ExprAst::Int(IntNode::new(3))));
            node}
        }
    }
    assert!(test_case!("let").is_let());
    assert!(test_case!("if").is_if());
    assert!(test_case!("lambda").is_lambda());
    assert!(test_case!("cond").is_cond());
    assert!(test_case!("set!").is_assign());
    assert!(test_case!("cond").is_cond());
    assert!(test_case!("begin").is_begin());
}
<|endoftext|>


<commit_before>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() { }

#[cfg(not(test))]
pub fn sti() {
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() { }

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts {
            guarded: guarded,
        }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        ClearLocalInterruptsGuardMut { guarded: &mut self.guarded, acquired: ATOMIC_BOOL_INIT }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        ClearLocalInterruptsGuard { guarded: &self.guarded, acquired: ATOMIC_BOOL_INIT }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = &g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<commit_msg>Fix test borrowing<commit_after>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() { }

#[cfg(not(test))]
pub fn sti() {
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() { }

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts {
            guarded: guarded,
        }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        ClearLocalInterruptsGuardMut { guarded: &mut self.guarded, acquired: ATOMIC_BOOL_INIT }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        ClearLocalInterruptsGuard { guarded: &self.guarded, acquired: ATOMIC_BOOL_INIT }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) {
            if CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
                cli();
            }
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(!are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<|endoftext|>


<commit_before>/// Supply the command line.

use std::fmt;

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

// TODO: figure out a way, eventually, to customize arguments based on whatever
// external tools are supplied---without requiring a rebuild. (Compare what
// Cargo does.)
pub fn cli<'a, 'b>(
    additional_args: &[Arg<'a, 'b>],
    additional_subcommands: &[App<'a, 'b>])
    -> ArgMatches<'a> {

  let mut args = vec![];
  args.extend_from_slice(additional_args);

  let mut subcommands = vec![
    generate(),
    new(),
  ];

  subcommands.extend_from_slice(additional_subcommands);

  App::new("SSG(rs)")
    .setting(AppSettings::ArgRequiredElseHelp)
    .version("0.1.0")
    .author(crate_authors!())
    .about("Meets my peculiar needs for generating static sites... *fast*.")
    .subcommands(subcommands)
    .args(&args)
    .get_matches()
}

// TODO: figure out what the best way to programmatically generate new options
// for these based on the state of the file system where it's run is, so that
// e.g. the user (*me*, initially!) can e.g. just specify a location for
// new templates in the configuration file, drop a template in there, and have
// the generator pick it up correctly as one of the options.
pub enum Commands {
  Generate,
  New,
  Unspecified,
}

impl fmt::Display for Commands {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self {
      &Commands::Generate => write!(f, "generate"),
      &Commands::New => write!(f, "new"),
      &Commands::Unspecified => write!(f, "error!!!"),  // TODO: something else!
    }
  }
}

impl<'a> From<&'a str> for Commands {
  fn from(s: &str) -> Commands {
    match s {
      "generate" => Commands::Generate,
      "new" => Commands::New,
      _ => Commands::Unspecified
    }
  }
}

// -- TODO: I feel like the following should be namespaced somehow?

/// Generate the site.
fn generate<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("generate")
    .about("Generate the site")
    .arg(Arg::with_name("local")
      .help("Use local paths to resources")
      .long("local"))
    .arg(Arg::with_name("serve")
      .short("s")
      .long("serve")
      .alias("server"))
}

/// Generate a new item from a template.
///
/// TODO: different templates will take different args, right?
fn new<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("new")
    .about("Create an item from a template")
    .arg(Arg::with_name("template")
      .help("The name of the template to generate, e.g. `post`")
      .index(1)
      .required(true)
      .possible_values(&["post"]))
    .arg(Arg::with_name("title")
      .help("The title to use in the template")
      .index(2)
      .required(true)
      .takes_value(true))
}
<commit_msg>Clean up Commands Display impl. :tada:<commit_after>/// Supply the command line.

use std::fmt;

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

// TODO: figure out a way, eventually, to customize arguments based on whatever
// external tools are supplied---without requiring a rebuild. (Compare what
// Cargo does.)
pub fn cli<'a, 'b>(
    additional_args: &[Arg<'a, 'b>],
    additional_subcommands: &[App<'a, 'b>])
    -> ArgMatches<'a> {

  let mut args = vec![];
  args.extend_from_slice(additional_args);

  let mut subcommands = vec![
    generate(),
    new(),
  ];

  subcommands.extend_from_slice(additional_subcommands);

  App::new("SSG(rs)")
    .setting(AppSettings::ArgRequiredElseHelp)
    .version("0.1.0")
    .author(crate_authors!())
    .about("Meets my peculiar needs for generating static sites... *fast*.")
    .subcommands(subcommands)
    .args(&args)
    .get_matches()
}

// TODO: figure out what the best way to programmatically generate new options
// for these based on the state of the file system where it's run is, so that
// e.g. the user (*me*, initially!) can e.g. just specify a location for
// new templates in the configuration file, drop a template in there, and have
// the generator pick it up correctly as one of the options.
pub enum Commands {
  Generate,
  New,
  Unspecified,
}

impl fmt::Display for Commands {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Commands::Generate => write!(f, "generate"),
      Commands::New => write!(f, "new"),
      _ => write!(f, "error!!!"),  // TODO: something else!
    }
  }
}

impl<'a> From<&'a str> for Commands {
  fn from(s: &str) -> Commands {
    match s {
      "generate" => Commands::Generate,
      "new" => Commands::New,
      _ => Commands::Unspecified
    }
  }
}

// -- TODO: I feel like the following should be namespaced somehow?

/// Generate the site.
fn generate<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("generate")
    .about("Generate the site")
    .arg(Arg::with_name("local")
      .help("Use local paths to resources")
      .long("local"))
    .arg(Arg::with_name("serve")
      .short("s")
      .long("serve")
      .alias("server"))
}

/// Generate a new item from a template.
///
/// TODO: different templates will take different args, right?
fn new<'a, 'b>() -> App<'a, 'b> {
  SubCommand::with_name("new")
    .about("Create an item from a template")
    .arg(Arg::with_name("template")
      .help("The name of the template to generate, e.g. `post`")
      .index(1)
      .required(true)
      .possible_values(&["post"]))
    .arg(Arg::with_name("title")
      .help("The title to use in the template")
      .index(2)
      .required(true)
      .takes_value(true))
}
<|endoftext|>


<commit_before>//! CPU Emulator
//!
//! Emulates the SynCpu architecture.

use byteorder::{LittleEndian, ReadBytesExt};
use instruction::{SynInt, Instruction};

use std::char;
use std::io::{Cursor, Error, stdin, Read};
use std::convert::From;
use std::fmt;

/// The size of RAM for 15-bit addressing.
const RAM_SIZE: usize = 32768;

/// The different error states that the CPU can encounter
#[derive(Debug)]
pub enum SynCpuErr {
    /// There was no error
    Ok,
    /// A pop instruction with an empty stack is an error
    PopOnEmptyStack,
    /// The CPU attempted to read an invalid instruction
    InstructionParseError(Error),
    /// The CPU does not yet support the given instruction
    UnimplementedInstruction(Instruction),
}

impl From<Error> for SynCpuErr {
    #[inline]
    fn from(val: Error) -> SynCpuErr {
        SynCpuErr::InstructionParseError(val)
    }
}

impl fmt::Display for SynCpuErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SynCpuErr::*;
        match *self {
            Ok => write!(f, "Ok"),
            PopOnEmptyStack => write!(f, "Pop called on empty stack"),
            InstructionParseError(ref err) => write!(f, "Instruction parse error: {}", err),
            UnimplementedInstruction(instr) => write!(f, "Unimplemented instruction: {}", instr),
        }
    }
}

/// An emulator for the SynCpu architecture.
pub struct SynCpu {
    /// The programme counter
    pub pc: u16,
    /// Eight 16-bit registers in the CPU
    pub registers: [u16; 8],
    /// Memory with 15-bit address space storing 16-bit values
    pub ram: [u16; RAM_SIZE],
    /// An unbounded stack which holds individual 16-bit values
    pub stack: Vec<u16>,
    /// Set to true if the execution has halted.
    pub halted: bool,
    /// An enum describing the error that halted execution, if any.
    pub error: SynCpuErr,
}

/// Tests whether a given SynInt is a register or a literal
#[inline]
pub fn is_reg(x: SynInt) -> bool {
    (x as usize) >= RAM_SIZE
}

/// Converts a given SynInt into a String
pub fn syn_int_str(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("{}", x)
    }
}

/// Converts a given SynInt into a String. Display literals as hex values.
pub fn syn_int_str_hex(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("0x{:0>4x}", x)
    }
}

impl SynCpu {

    /// Converts the given SynInt into a literal value, either directly
    /// or by reading a register
    #[inline]
    fn val(&self, x: SynInt) -> u16 {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE]
        } else {
            x
        }
    }

    /// Sets the value of the register specified by x to the value a.
    #[inline]
    fn set_reg(&mut self, x: SynInt, a: u16) {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE] = a;
        }
    }

    /// Constructs a new emulator given an input program.
    pub fn new(program: &[u8]) -> Result<SynCpu, SynCpuErr> {
        let mut cpu = SynCpu {
            pc: 0,
            registers: [0; 8],
            ram: [0xbeef; RAM_SIZE],
            stack: Vec::new(),
            halted: false,
            error: SynCpuErr::Ok,
        };

        let prog_len = program.len();
        let mut rdr = Cursor::new(program);
        let mut i = 0;

        while rdr.position() != prog_len as u64 {
            cpu.ram[i] = rdr.read_u16::<LittleEndian>()?;
            i += 1;
        }

        Ok(cpu)
    }

    /// Returns the instruction contained at the program counter offset in memory.
    #[inline]
    pub fn next_instruction(&self) -> Instruction {
        self.instruction_at(self.pc as usize)
    }

    /// Returns the instruction contained at the given offset in memory.
    #[inline]
    pub fn instruction_at(&self, offset: usize) -> Instruction {
        Instruction::read_instr(&self.ram[offset..])
    }

    /// Exectue a single instruction on the CPU.
    pub fn step(&mut self) {

        // If the CPU has halted already, stop.
        if self.halted {
            return;
        }

        // Read the instruction from memory at the program counter
        use instruction::Instruction::*;
        let instr = self.next_instruction();

        // Execute the instruction
        match instr {
            Halt => {
                self.halted = true;
            },

            Set { dst, a } => {
                let val = self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Push { src } => {
                let v = self.val(src);
                self.stack.push(v);
                self.pc += instr.size();
            },
            Pop { dst } => {
                if self.stack.is_empty() {
                    self.halted = true;
                    self.error = SynCpuErr::PopOnEmptyStack;
                }
                let val = self.stack.pop().unwrap();
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Eq { dst, a, b } => {
                let val = if self.val(a) == self.val(b) {
                    1
                } else {
                    0
                };

                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Gt { dst, a, b } => {
                let val = if self.val(a) > self.val(b) {
                    1
                } else {
                    0
                };
                self.set_reg(dst, val);
                self.pc += instr.size();
            },

            Jmp { dst } => {
                self.pc = dst;
            },
            Jt { src, dst } => {
                if self.val(src) != 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },
            Jf { src, dst } => {
                if self.val(src) == 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },

            Add { dst, a, b } => {
                let sum = (self.val(a) as u64) + (self.val(b) as u64);
                self.set_reg(dst, (sum % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mult { dst, a, b } => {
                let mul = (self.val(a) as u64) * (self.val(b) as u64);
                self.set_reg(dst, (mul % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mod { dst, a, b } => {
                let mul = self.val(a) % self.val(b);
                self.set_reg(dst, mul);
                self.pc += instr.size();
            },
            And { dst, a, b } => {
                let val = self.val(a) & self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Or { dst, a, b } => {
                let val = self.val(a) | self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Not { dst, a } => {
                let val = 0b111111111111111 ^ self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            ReadMem { dst, src } => {
                let address = self.val(src);
                let val = self.ram[address as usize];
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            WriteMem { dst, src } => {
                let address = self.val(dst);
                self.ram[address as usize] = self.val(src);
                self.pc += instr.size();
            },
            Call { dst } => {
                let next_instr = self.pc + instr.size();
                self.stack.push(next_instr);
                self.pc = self.val(dst);
            },
            Ret => {
                if self.stack.is_empty() {
                    self.halted = true;
                }
                let val = self.stack.pop().unwrap();
                self.pc = val;
            }
            Out { value } => {
                print!("{}", char::from_u32(self.val(value) as u32).unwrap());
                self.pc += instr.size();
            },
            In { dst } => {
                let mut buf = [0; 1];
                stdin().read_exact(&mut buf).unwrap();
                self.set_reg(dst, buf[0] as u16);
                self.pc += instr.size();
            },
            Noop => { self.pc += 1; },
            _ => {
                self.halted = true;
                self.error = SynCpuErr::UnimplementedInstruction(instr);
            }
        };
    }

}
<commit_msg>Fixed `in` opcode on Windows.<commit_after>//! CPU Emulator
//!
//! Emulates the SynCpu architecture.

use byteorder::{LittleEndian, ReadBytesExt};
use instruction::{SynInt, Instruction};

use std::char;
use std::io::{Cursor, Error, stdin, Read};
use std::convert::From;
use std::fmt;

/// The size of RAM for 15-bit addressing.
const RAM_SIZE: usize = 32768;

/// The different error states that the CPU can encounter
#[derive(Debug)]
pub enum SynCpuErr {
    /// There was no error
    Ok,
    /// A pop instruction with an empty stack is an error
    PopOnEmptyStack,
    /// The CPU attempted to read an invalid instruction
    InstructionParseError(Error),
    /// The CPU does not yet support the given instruction
    UnimplementedInstruction(Instruction),
}

impl From<Error> for SynCpuErr {
    #[inline]
    fn from(val: Error) -> SynCpuErr {
        SynCpuErr::InstructionParseError(val)
    }
}

impl fmt::Display for SynCpuErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SynCpuErr::*;
        match *self {
            Ok => write!(f, "Ok"),
            PopOnEmptyStack => write!(f, "Pop called on empty stack"),
            InstructionParseError(ref err) => write!(f, "Instruction parse error: {}", err),
            UnimplementedInstruction(instr) => write!(f, "Unimplemented instruction: {}", instr),
        }
    }
}

/// An emulator for the SynCpu architecture.
pub struct SynCpu {
    /// The programme counter
    pub pc: u16,
    /// Eight 16-bit registers in the CPU
    pub registers: [u16; 8],
    /// Memory with 15-bit address space storing 16-bit values
    pub ram: [u16; RAM_SIZE],
    /// An unbounded stack which holds individual 16-bit values
    pub stack: Vec<u16>,
    /// Set to true if the execution has halted.
    pub halted: bool,
    /// An enum describing the error that halted execution, if any.
    pub error: SynCpuErr,
}

/// Tests whether a given SynInt is a register or a literal
#[inline]
pub fn is_reg(x: SynInt) -> bool {
    (x as usize) >= RAM_SIZE
}

/// Converts a given SynInt into a String
pub fn syn_int_str(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("{}", x)
    }
}

/// Converts a given SynInt into a String. Display literals as hex values.
pub fn syn_int_str_hex(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("0x{:0>4x}", x)
    }
}

impl SynCpu {

    /// Converts the given SynInt into a literal value, either directly
    /// or by reading a register
    #[inline]
    fn val(&self, x: SynInt) -> u16 {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE]
        } else {
            x
        }
    }

    /// Sets the value of the register specified by x to the value a.
    #[inline]
    fn set_reg(&mut self, x: SynInt, a: u16) {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE] = a;
        }
    }

    /// Constructs a new emulator given an input program.
    pub fn new(program: &[u8]) -> Result<SynCpu, SynCpuErr> {
        let mut cpu = SynCpu {
            pc: 0,
            registers: [0; 8],
            ram: [0xbeef; RAM_SIZE],
            stack: Vec::new(),
            halted: false,
            error: SynCpuErr::Ok,
        };

        let prog_len = program.len();
        let mut rdr = Cursor::new(program);
        let mut i = 0;

        while rdr.position() != prog_len as u64 {
            cpu.ram[i] = rdr.read_u16::<LittleEndian>()?;
            i += 1;
        }

        Ok(cpu)
    }

    /// Returns the instruction contained at the program counter offset in memory.
    #[inline]
    pub fn next_instruction(&self) -> Instruction {
        self.instruction_at(self.pc as usize)
    }

    /// Returns the instruction contained at the given offset in memory.
    #[inline]
    pub fn instruction_at(&self, offset: usize) -> Instruction {
        Instruction::read_instr(&self.ram[offset..])
    }

    /// Exectue a single instruction on the CPU.
    pub fn step(&mut self) {

        // If the CPU has halted already, stop.
        if self.halted {
            return;
        }

        // Read the instruction from memory at the program counter
        use instruction::Instruction::*;
        let instr = self.next_instruction();

        // Execute the instruction
        match instr {
            Halt => {
                self.halted = true;
            },

            Set { dst, a } => {
                let val = self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Push { src } => {
                let v = self.val(src);
                self.stack.push(v);
                self.pc += instr.size();
            },
            Pop { dst } => {
                if self.stack.is_empty() {
                    self.halted = true;
                    self.error = SynCpuErr::PopOnEmptyStack;
                }
                let val = self.stack.pop().unwrap();
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Eq { dst, a, b } => {
                let val = if self.val(a) == self.val(b) {
                    1
                } else {
                    0
                };

                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Gt { dst, a, b } => {
                let val = if self.val(a) > self.val(b) {
                    1
                } else {
                    0
                };
                self.set_reg(dst, val);
                self.pc += instr.size();
            },

            Jmp { dst } => {
                self.pc = dst;
            },
            Jt { src, dst } => {
                if self.val(src) != 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },
            Jf { src, dst } => {
                if self.val(src) == 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },

            Add { dst, a, b } => {
                let sum = (self.val(a) as u64) + (self.val(b) as u64);
                self.set_reg(dst, (sum % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mult { dst, a, b } => {
                let mul = (self.val(a) as u64) * (self.val(b) as u64);
                self.set_reg(dst, (mul % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mod { dst, a, b } => {
                let mul = self.val(a) % self.val(b);
                self.set_reg(dst, mul);
                self.pc += instr.size();
            },
            And { dst, a, b } => {
                let val = self.val(a) & self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Or { dst, a, b } => {
                let val = self.val(a) | self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Not { dst, a } => {
                let val = 0b111111111111111 ^ self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            ReadMem { dst, src } => {
                let address = self.val(src);
                let val = self.ram[address as usize];
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            WriteMem { dst, src } => {
                let address = self.val(dst);
                self.ram[address as usize] = self.val(src);
                self.pc += instr.size();
            },
            Call { dst } => {
                let next_instr = self.pc + instr.size();
                self.stack.push(next_instr);
                self.pc = self.val(dst);
            },
            Ret => {
                if self.stack.is_empty() {
                    self.halted = true;
                }
                let val = self.stack.pop().unwrap();
                self.pc = val;
            }
            Out { value } => {
                print!("{}", char::from_u32(self.val(value) as u32).unwrap());
                self.pc += instr.size();
            },
            In { dst } => {
                let mut buf = [0; 1];
                stdin().read_exact(&mut buf).unwrap();

		        if buf[0] == 13 {
		            return;
		        }

                self.set_reg(dst, buf[0] as u16);
                self.pc += instr.size();
            },
            Noop => { self.pc += 1; },
            _ => {
                self.halted = true;
                self.error = SynCpuErr::UnimplementedInstruction(instr);
            }
        };
    }

}
<|endoftext|>


<commit_before>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>(_: &T) -> usize { 4 }
    }
}
<commit_msg>Add dox::{Copy, Clone} impls for pointer and integer types.<commit_after>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    impl<T> Copy for *mut T {}
    impl<T> Clone for *mut T {
        fn clone(&self) -> *mut T { loop {} }
    }

    impl<T> Copy for *const T {}
    impl<T> Clone for *const T {
        fn clone(&self) -> *const T { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
            impl Copy for $i {}
            impl Clone for $i {
                fn clone(&self) -> $i { loop {} }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>(_: &T) -> usize { 4 }
    }
}
<|endoftext|>


<commit_before>use std::slice;

extern crate libc;
use self::libc::{c_void, c_double, size_t};

use super::geo::{Point, Polygon, LineString};

use super::polylabel;
use super::num::{Float};

/// Wrapper for a void pointer to a sequence of [`Array`](struct.Array.html)s, and the sequence length
///
/// Used for inner Polygon rings
#[repr(C)]
pub struct WrapperArray {
    pub data: *const Array,
    pub len: size_t,
}

/// Wrapper for a void pointer to a sequence of 2-element arrays representing points, and the sequence length
///
/// Used for outer Polygon rings. `data` is a `Vec<[c_double; 2]>`
#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

/// FFI struct for returned optimum Polygon label position
#[repr(C)]
pub struct Position {
    pub x_pos: c_double,
    pub y_pos: c_double,
}

// convert a Polylabel result Point into values that can be sent across the FFI boundary
impl<T> From<Point<T>> for Position
    where T: Float
{
    fn from(point: Point<T>) -> Position {
        Position {
            x_pos: point.x().to_f64().unwrap() as c_double,
            y_pos: point.y().to_f64().unwrap() as c_double,
        }
    }
}

fn reconstitute(arr: &Array) -> Vec<[f64; 2]> {
    unsafe { slice::from_raw_parts(arr.data as *mut [f64; 2], arr.len).to_vec() }
}

fn reconstitute2(arr: WrapperArray) -> Vec<Vec<[f64; 2]>> {
    let arrays = unsafe { slice::from_raw_parts(arr.data as *mut Array, arr.len) };
    arrays.into_iter().map(|x| reconstitute(x)).collect()
}

/// FFI access to the [`polylabel`](fn.polylabel.html) function
///
/// Accepts three arguments: an exterior ring [`Array`](struct.Array.html), an interior rings [`WrapperArray`](struct.WrapperArray.html), and a tolerance `c_float`.
#[no_mangle]
pub extern "C" fn polylabel_ffi(outer: Array,
                                inners: WrapperArray,
                                tolerance: c_double)
                                -> Position {
    let exterior: Vec<[f64; 2]> =
        unsafe { slice::from_raw_parts(outer.data as *mut [c_double; 2], outer.len).to_vec() };
    let interior: Vec<Vec<[f64; 2]>> = reconstitute2(inners);
    let ls_ext = LineString(exterior.iter().map(|e| Point::new(e[0], e[1])).collect());
    let ls_int: Vec<LineString<c_double>> = interior.iter()
        .map(|vec| LineString(vec.iter().map(|e| Point::new(e[0], e[1])).collect()))
        .collect();

    let poly = Polygon(ls_ext, ls_int);
    polylabel(&poly, &tolerance).into()
}

#[cfg(test)]
mod tests {
    use super::{Array, WrapperArray, reconstitute2};
    use super::libc::{c_void, size_t};
    use std::mem;

    // Only used for testing
    fn gen_array(v: Vec<[f64; 2]>) -> Array {
        let array = Array {
            data: v.as_ptr() as *const c_void,
            len: v.len() as size_t,
        };
        mem::forget(v);
        array
    }
    // only used for testing
    fn gen_wrapperarray(v: Vec<Vec<[f64; 2]>>) -> WrapperArray {
        let converted: Vec<Array> = v.into_iter().map(|x| gen_array(x)).collect();
        let array2 = WrapperArray {
            data: converted.as_ptr() as *const Array,
            len: converted.len() as size_t,
        };
        mem::forget(converted);
        array2
    }
    #[test]
    fn test_array() {
        let i_a = vec![[0.5, 0.5], [1.0, 1.0], [1.5, 0.5]];
        let i_b = vec![[0.55, 0.55], [0.8, 0.8], [1.2, 0.55]];
        let inners = vec![i_a, i_b];
        let array = gen_wrapperarray(inners);
        let rec_inners = reconstitute2(array);
        assert_eq!(rec_inners[0][2], [1.5, 0.5])
    }

}
<commit_msg>Rustfmt changes<commit_after>use std::slice;

extern crate libc;
use self::libc::{c_void, c_double, size_t};

use super::geo::{Point, Polygon, LineString};

use super::polylabel;
use super::num::Float;

/// Wrapper for a void pointer to a sequence of [`Array`](struct.Array.html)s, and the sequence length
///
/// Used for inner Polygon rings
#[repr(C)]
pub struct WrapperArray {
    pub data: *const Array,
    pub len: size_t,
}

/// Wrapper for a void pointer to a sequence of 2-element arrays representing points, and the sequence length
///
/// Used for outer Polygon rings. `data` is a `Vec<[c_double; 2]>`
#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

/// FFI struct for returned optimum Polygon label position
#[repr(C)]
pub struct Position {
    pub x_pos: c_double,
    pub y_pos: c_double,
}

// convert a Polylabel result Point into values that can be sent across the FFI boundary
impl<T> From<Point<T>> for Position
    where T: Float
{
    fn from(point: Point<T>) -> Position {
        Position {
            x_pos: point.x().to_f64().unwrap() as c_double,
            y_pos: point.y().to_f64().unwrap() as c_double,
        }
    }
}

fn reconstitute(arr: &Array) -> Vec<[f64; 2]> {
    unsafe { slice::from_raw_parts(arr.data as *mut [f64; 2], arr.len).to_vec() }
}

fn reconstitute2(arr: WrapperArray) -> Vec<Vec<[f64; 2]>> {
    let arrays = unsafe { slice::from_raw_parts(arr.data as *mut Array, arr.len) };
    arrays.into_iter().map(|x| reconstitute(x)).collect()
}

/// FFI access to the [`polylabel`](fn.polylabel.html) function
///
/// Accepts three arguments: an exterior ring [`Array`](struct.Array.html), an interior rings [`WrapperArray`](struct.WrapperArray.html), and a tolerance `c_float`.
#[no_mangle]
pub extern "C" fn polylabel_ffi(outer: Array,
                                inners: WrapperArray,
                                tolerance: c_double)
                                -> Position {
    let exterior: Vec<[f64; 2]> =
        unsafe { slice::from_raw_parts(outer.data as *mut [c_double; 2], outer.len).to_vec() };
    let interior: Vec<Vec<[f64; 2]>> = reconstitute2(inners);
    let ls_ext = LineString(exterior.iter().map(|e| Point::new(e[0], e[1])).collect());
    let ls_int: Vec<LineString<c_double>> = interior.iter()
        .map(|vec| LineString(vec.iter().map(|e| Point::new(e[0], e[1])).collect()))
        .collect();

    let poly = Polygon(ls_ext, ls_int);
    polylabel(&poly, &tolerance).into()
}

#[cfg(test)]
mod tests {
    use super::{Array, WrapperArray, reconstitute2};
    use super::libc::{c_void, size_t};
    use std::mem;

    // Only used for testing
    fn gen_array(v: Vec<[f64; 2]>) -> Array {
        let array = Array {
            data: v.as_ptr() as *const c_void,
            len: v.len() as size_t,
        };
        mem::forget(v);
        array
    }
    // only used for testing
    fn gen_wrapperarray(v: Vec<Vec<[f64; 2]>>) -> WrapperArray {
        let converted: Vec<Array> = v.into_iter().map(|x| gen_array(x)).collect();
        let array2 = WrapperArray {
            data: converted.as_ptr() as *const Array,
            len: converted.len() as size_t,
        };
        mem::forget(converted);
        array2
    }
    #[test]
    fn test_array() {
        let i_a = vec![[0.5, 0.5], [1.0, 1.0], [1.5, 0.5]];
        let i_b = vec![[0.55, 0.55], [0.8, 0.8], [1.2, 0.55]];
        let inners = vec![i_a, i_b];
        let array = gen_wrapperarray(inners);
        let rec_inners = reconstitute2(array);
        assert_eq!(rec_inners[0][2], [1.5, 0.5])
    }

}
<|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};

pub struct Git {
    pub host: String,
    pub token: String,
    repo_dir: PathBuf,
}

impl Git {
    pub fn new(host: &str, token: &str, repo_dir: &Path) -> Git {
        Git {
            host: host.to_string(),
            token: token.to_string(),
            repo_dir: repo_dir.to_owned(),
        }
    }

    pub fn run(&self, args: &[&str]) -> Result<String, String> {
        self.do_run(args, None)
    }

    pub fn run_with_stdin(&self, args: &[&str], stdin: &str) -> Result<String, String> {
        self.do_run(args, Some(stdin))
    }

    fn ask_pass_path(&self) -> String {
        let ask_pass = "octobot-ask-pass";
        match env::current_exe() {
            Ok(ref exe) if exe.parent().is_some() => {
                exe.parent().unwrap().join(ask_pass).to_string_lossy().into_owned()
            }
            _ => ask_pass.to_string(),
        }
    }

    pub fn has_branch(&self, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch"]));
        Ok(Git::branches_output_contains(&output, branch))
    }

    pub fn current_branch(&self) -> Result<String, String> {
        self.run(&["rev-parse", "--abbrev-ref", "HEAD"])
    }

    pub fn does_branch_contain(&self, git_ref: &str, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch", "--contains", git_ref]));
        Ok(Git::branches_output_contains(&output, branch))
    }

    fn branches_output_contains(output: &str, branch: &str) -> bool {
        // Output is trimmed, so first entry (if not current branch) won't have an asterisk.
        // Otherwise, skip two characters to account for alignment w/ asterisk.
        output.lines().any(|b| b == branch || b.len() > 2 && branch == &b[2..])
    }

    // Find the commit at which |leaf_ref| forked from |base_branch|.
    // This can find which commits belong to a PR.
    // Returns the ref found in the base branch that this git_ref came from.
    pub fn find_base_branch_commit(&self, leaf_ref: &str, base_branch: &str) -> Result<String, String> {
        match self.run(&["merge-base", "--fork-point", base_branch, leaf_ref]) {
            Ok(base) => Ok(base),
            Err(_) => self.run(&["merge-base", base_branch, leaf_ref]),
        }
    }

    pub fn clean(&self) -> Result<(), String> {
        try!(self.run(&["reset", "--hard"]));
        try!(self.run(&["clean", "-fdx"]));
        Ok(())
    }

    // checking a branch named |new_branch_name| and ensure it is up to date with |source_ref|
    // |source_ref| can be a commit hash or an origin/branch-name.
    pub fn checkout_branch(&self, new_branch_name: &str, source_ref: &str) ->  Result<(), String> {
        try!(self.run(&["checkout", "-B", new_branch_name, source_ref]));
        Ok(())
    }

    pub fn diff(&self, base: &str, head: &str) -> Result<String, String> {
        self.run(&["diff", base, head, "-w"])
    }

    // returns (title, body)
    pub fn get_commit_desc(&self, commit_hash: &str) -> Result<(String, String), String> {
        let message = try!(self.run(&["log", "-1", "--pretty=%B", commit_hash]));

        let mut lines = message.lines();
        let title: String = lines.next().unwrap_or("").into();
        let body: Vec<&str> = lines.skip_while(|ref l| l.trim().len() == 0).collect();

        Ok((title, body.join("\n")))
    }

    fn do_run(&self, args: &[&str], stdin: Option<&str>) -> Result<String, String> {
        debug!("Running git with args: {:?}", args);
        let cmd = Command::new("git")
            .current_dir(&self.repo_dir)
            .stdin(if stdin.is_some() {
                Stdio::piped()
            } else {
                Stdio::null()
            })
            .stderr(Stdio::piped())
            .stdout(Stdio::piped())
            .args(args)
            .env("GIT_ASKPASS", &self.ask_pass_path())
            .env("OCTOBOT_HOST", &self.host)
            .env("OCTOBOT_PASS", &self.token)
            .spawn();

        let mut child = match cmd {
            Ok(c) => c,
            Err(e) => return Err(format!("Error starting git: {}", e)),
        };

        if let Some(ref stdin) = stdin {
            if let Some(ref mut child_stdin) = child.stdin {
                if let Err(e) = child_stdin.write_all(stdin.as_bytes()) {
                    return Err(format!("Error writing to stdin: {}", e));
                }
            }
        }

        let result = match child.wait_with_output() {
            Ok(r) => r,
            Err(e) => return Err(format!("Error running git: {}", e)),
        };

        let mut output = String::new();
        if result.stdout.len() > 0 {
            output += String::from_utf8_lossy(&result.stdout).as_ref();
        }

        if !result.status.success() {
            if result.stderr.len() > 0 {
                output += String::from_utf8_lossy(&result.stderr).as_ref();
            }
            Err(format!("Error running git (exit code {}):\n{}",
                        result.status.code().unwrap_or(-1),
                        output))
        } else {

            Ok(output.trim().to_string())
        }
    }
}

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

    #[test]
    fn test_branches_output_contains() {
        assert!(Git::branches_output_contains("test", "test"));
        assert!(Git::branches_output_contains("* test", "test"));
        assert!(!Git::branches_output_contains("* tests", "test"));

        assert!(Git::branches_output_contains("test\ntwo", "two"));
        assert!(Git::branches_output_contains("test\n* two", "two"));
        assert!(!Git::branches_output_contains("test\n* twos", "two"));
    }
}
<commit_msg>Include git args in error messages (#67)<commit_after>use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};

pub struct Git {
    pub host: String,
    pub token: String,
    repo_dir: PathBuf,
}

impl Git {
    pub fn new(host: &str, token: &str, repo_dir: &Path) -> Git {
        Git {
            host: host.to_string(),
            token: token.to_string(),
            repo_dir: repo_dir.to_owned(),
        }
    }

    pub fn run(&self, args: &[&str]) -> Result<String, String> {
        self.do_run(args, None)
    }

    pub fn run_with_stdin(&self, args: &[&str], stdin: &str) -> Result<String, String> {
        self.do_run(args, Some(stdin))
    }

    fn ask_pass_path(&self) -> String {
        let ask_pass = "octobot-ask-pass";
        match env::current_exe() {
            Ok(ref exe) if exe.parent().is_some() => {
                exe.parent().unwrap().join(ask_pass).to_string_lossy().into_owned()
            }
            _ => ask_pass.to_string(),
        }
    }

    pub fn has_branch(&self, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch"]));
        Ok(Git::branches_output_contains(&output, branch))
    }

    pub fn current_branch(&self) -> Result<String, String> {
        self.run(&["rev-parse", "--abbrev-ref", "HEAD"])
    }

    pub fn does_branch_contain(&self, git_ref: &str, branch: &str) -> Result<bool, String> {
        let output = try!(self.run(&["branch", "--contains", git_ref]));
        Ok(Git::branches_output_contains(&output, branch))
    }

    fn branches_output_contains(output: &str, branch: &str) -> bool {
        // Output is trimmed, so first entry (if not current branch) won't have an asterisk.
        // Otherwise, skip two characters to account for alignment w/ asterisk.
        output.lines().any(|b| b == branch || b.len() > 2 && branch == &b[2..])
    }

    // Find the commit at which |leaf_ref| forked from |base_branch|.
    // This can find which commits belong to a PR.
    // Returns the ref found in the base branch that this git_ref came from.
    pub fn find_base_branch_commit(&self, leaf_ref: &str, base_branch: &str) -> Result<String, String> {
        match self.run(&["merge-base", "--fork-point", base_branch, leaf_ref]) {
            Ok(base) => Ok(base),
            Err(_) => self.run(&["merge-base", base_branch, leaf_ref]),
        }
    }

    pub fn clean(&self) -> Result<(), String> {
        try!(self.run(&["reset", "--hard"]));
        try!(self.run(&["clean", "-fdx"]));
        Ok(())
    }

    // checking a branch named |new_branch_name| and ensure it is up to date with |source_ref|
    // |source_ref| can be a commit hash or an origin/branch-name.
    pub fn checkout_branch(&self, new_branch_name: &str, source_ref: &str) ->  Result<(), String> {
        try!(self.run(&["checkout", "-B", new_branch_name, source_ref]));
        Ok(())
    }

    pub fn diff(&self, base: &str, head: &str) -> Result<String, String> {
        self.run(&["diff", base, head, "-w"])
    }

    // returns (title, body)
    pub fn get_commit_desc(&self, commit_hash: &str) -> Result<(String, String), String> {
        let message = try!(self.run(&["log", "-1", "--pretty=%B", commit_hash]));

        let mut lines = message.lines();
        let title: String = lines.next().unwrap_or("").into();
        let body: Vec<&str> = lines.skip_while(|ref l| l.trim().len() == 0).collect();

        Ok((title, body.join("\n")))
    }

    fn do_run(&self, args: &[&str], stdin: Option<&str>) -> Result<String, String> {
        debug!("Running git with args: {:?}", args);
        let cmd = Command::new("git")
            .current_dir(&self.repo_dir)
            .stdin(if stdin.is_some() {
                Stdio::piped()
            } else {
                Stdio::null()
            })
            .stderr(Stdio::piped())
            .stdout(Stdio::piped())
            .args(args)
            .env("GIT_ASKPASS", &self.ask_pass_path())
            .env("OCTOBOT_HOST", &self.host)
            .env("OCTOBOT_PASS", &self.token)
            .spawn();

        let mut child = match cmd {
            Ok(c) => c,
            Err(e) => return Err(format!("Error starting git (args: {:?}): {}", args, e)),
        };

        if let Some(ref stdin) = stdin {
            if let Some(ref mut child_stdin) = child.stdin {
                if let Err(e) = child_stdin.write_all(stdin.as_bytes()) {
                    return Err(format!("Error writing to stdin: {}", e));
                }
            }
        }

        let result = match child.wait_with_output() {
            Ok(r) => r,
            Err(e) => return Err(format!("Error running git (args: {:?}): {}", args, e)),
        };

        let mut output = String::new();
        if result.stdout.len() > 0 {
            output += String::from_utf8_lossy(&result.stdout).as_ref();
        }

        if !result.status.success() {
            if result.stderr.len() > 0 {
                output += String::from_utf8_lossy(&result.stderr).as_ref();
            }
            Err(format!("Error running git (exit code {}, args: {:?}):\n{}",
                        result.status.code().unwrap_or(-1),
                        args,
                        output))
        } else {

            Ok(output.trim().to_string())
        }
    }
}

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

    #[test]
    fn test_branches_output_contains() {
        assert!(Git::branches_output_contains("test", "test"));
        assert!(Git::branches_output_contains("* test", "test"));
        assert!(!Git::branches_output_contains("* tests", "test"));

        assert!(Git::branches_output_contains("test\ntwo", "two"));
        assert!(Git::branches_output_contains("test\n* two", "two"));
        assert!(!Git::branches_output_contains("test\n* twos", "two"));
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature};
use commit_analyzer::{self, CommitType};
use error::Error;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(repo: &Repository, signature: &Signature, message: &str) -> Result<(), git2::Error> {
    let update_ref = Some("HEAD");

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(update_ref, signature, signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(repo: &Repository, signature: &Signature, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let obj = try!(repo.revparse_single("HEAD"));

    repo.tag(tag_name, &obj, &signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(path: &str) -> Option<Version> {
    let repo = match Repository::open(path) {
        Ok(repo) => repo,
        Err(_) => return None
    };

    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(path: &str) -> CommitType {
    match latest_tag(path) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(path, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(path: &str, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let repo = Repository::open(path).expect("Open repository failed");

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    let tag = walker.map(|c| repo.find_commit(c).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown);

    tag
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(repository_path: &str, new_version: &str) -> Result<(), Error> {
    let repo = try!(Repository::open(repository_path));

    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&repo, &files[..]));

    let signature = try!(get_signature(&repo));
    commit(&repo, &signature, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(repository_path: &str, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    let repo = try!(Repository::open(repository_path));
    let signature = try!(get_signature(&repo));

    create_tag(&repo, &signature, &tag_name, &tag_message)
        .map_err(Error::from)
}
<commit_msg>fix: Handle Result returned from revwalk<commit_after>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature};
use commit_analyzer::{self, CommitType};
use error::Error;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(repo: &Repository, signature: &Signature, message: &str) -> Result<(), git2::Error> {
    let update_ref = Some("HEAD");

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(update_ref, signature, signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(repo: &Repository, signature: &Signature, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let obj = try!(repo.revparse_single("HEAD"));

    repo.tag(tag_name, &obj, &signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(path: &str) -> Option<Version> {
    let repo = match Repository::open(path) {
        Ok(repo) => repo,
        Err(_) => return None
    };

    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(path: &str) -> CommitType {
    match latest_tag(path) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(path, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(path: &str, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let repo = Repository::open(path).expect("Open repository failed");

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    let tag = walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown);

    tag
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(repository_path: &str, new_version: &str) -> Result<(), Error> {
    let repo = try!(Repository::open(repository_path));

    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&repo, &files[..]));

    let signature = try!(get_signature(&repo));
    commit(&repo, &signature, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(repository_path: &str, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    let repo = try!(Repository::open(repository_path));
    let signature = try!(get_signature(&repo));

    create_tag(&repo, &signature, &tag_name, &tag_message)
        .map_err(Error::from)
}
<|endoftext|>