<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Lionel Flandrin <lionel@svkt.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Driver for the Hitachi HD44780U LCD driver

use core::prelude::*;

use drivers::chario::CharIO;
use hal::pin::Gpio;
use hal::timer::Timer;

/// HD44780U driver context
pub struct Hd44780u<'a> {
  /// Timer used for protocol delays
  timer: &'a Timer + 'a,
  /// Register Selector wire
  rs:    &'a Gpio + 'a,
  /// Enable wire
  en:    &'a Gpio + 'a,
  /// The 4 data wires. Those must be wired to [d4, d5, d6, d7] in 4bit mode.
  data: [&'a Gpio + 'a, ..4],
}

/// The controller supports writing in either direction to accomodate various
/// languages.
pub enum MoveDir {
  /// Cursor moves right after write
  Right,
  /// Cursor moves left after write
  Left,
}

/// The controller supports 5x8 and 5x10 dot fonts depending on the LCD used.
pub enum Font {
  /// Use 5x8 dot matrix font
  Font5x8,
  /// Use 5x10 dot matrix font
  Font5x10,
}

impl<'a> Hd44780u<'a> {
  /// Construct an Hd44780u instance
  pub fn new<'a>(timer: &'a Timer + 'a,
                 rs:    &'a Gpio  + 'a,
                 en:    &'a Gpio  + 'a,
                 data: [&'a Gpio  + 'a, ..4]) -> Hd44780u<'a> {
    Hd44780u { timer: timer, rs: rs, en: en, data: data }
  }

  /// Power up sequence for 4bit mode as detailed in page 46 of the datasheet.
  /// The two_lines and font parameters are used to set the LCD parameters. See
  /// `function_set` for more details.
  pub fn init(&self, two_lines: bool, font: Font) {
    // Start by pulling RS and EN low
    self.rs.set_low();
    self.en.set_low();

    // We need to wait at least 40ms after the chip is powered before we can
    // talk to it. Assume that the power just went on and wait.
    self.timer.wait_ms(50);

    // Set interface to 8bit
    self.write_nibble(0b0011);

    // Wait 4.1ms
    self.timer.wait_us(4100);

    // Set interface to 8bit
    self.write_nibble(0b0011);

    // Wait 100us
    self.timer.wait_us(100);

    // Set interface to 8bit (for the last time...)
    self.write_nibble(0b0011);
    self.timer.wait_us(100);

    // We can now finally switch to 4bit
    self.write_nibble(0b0010);
    self.timer.wait_us(100);

    // Set function
    self.function_set(two_lines, font);

    self.display_control(true, false, false);

    self.clear();

    // Set default mode
    self.mode_set(MoveDir::Right, false);
  }

  /// Set cursor position to (`col`, `row`). (0, 0) is the top left.
  pub fn set_pos(&self, col: u8, row: u8) {
    // Rows are not continuous in DDRAM, there's a 0x40 offset between the
    // begining of each line.
    self.ddram_address_set(row * 0x40 + col);
  }

  /// Clear the entire display
  pub fn clear(&self) {
    self.instruction(0b0001);
    // I can't find in the datasheet how long this is supposed to take but it
    // seems to take at least a few ms.
    self.timer.wait_ms(5);
  }

  /// Return the cursor to the left of the first line of the display. Also
  /// returns the display to its original status if it was shifted (see
  /// `mode_set`).
  pub fn return_home(&self) {
    self.instruction(0b10);
    // This takes 1.52ms
    self.timer.wait_ms(2);
  }

  /// Set the writing direction and optional display shifting.
  ///
  /// If `shift_display` is true then when writing the cursor remains at the
  /// same place on the display and "pushes" existing data in the direction
  /// specified by dir.
  ///
  /// Calling `clear` resets the writing direction Right but does not change
  /// the display shift setting.
  pub fn mode_set(&self, dir: MoveDir, shift_display: bool) {
    let mut cmd = 0b100;

    let d = match dir {
      MoveDir::Right => 1,
      MoveDir::Left  => 0,
    };

    cmd |= d                     << 1;
    cmd |= (shift_display as u8) << 0;

    self.instruction(cmd);
  }

  /// Display control. If `on` is false nothing is displayed but the screen's
  /// contents remain in RAM and can be re-displayed at any moment. This
  /// function can also enable or disable the cursor and blinking.
  pub fn display_control(&self, on: bool, cursor: bool, blink: bool) {
    let mut cmd = 0b1000;

    cmd |= (on     as u8) << 2;
    cmd |= (cursor as u8) << 1;
    cmd |= (blink  as u8) << 0;

    self.instruction(cmd);
  }

  /// Shift cursor or display in a given direction
  pub fn shift(&self, dir: MoveDir, shift_display: bool) {
    let mut cmd = 0b10000;

    let d = match dir {
      MoveDir::Right => 1,
      MoveDir::Left  => 0,
    };

    cmd |= (shift_display as u8) << 3;
    cmd |= d                     << 2;

    self.instruction(cmd);
  }

  /// Set the bus width, number of lines and character font size. This function
  /// can only be called once in the init sequence.
  ///
  /// Only 4bit wide interfaces are supported for now.
  ///
  /// `two_lines` should be
  /// `false` if the display only has one line, true otherwise.
  ///
  /// If each display character is a matrix of 5x10 dots `char_5x10` should be
  /// `true`. If it's 5x8 dots set it to `false`.
  fn function_set(&self, two_lines: bool, font: Font) {
    use self::Font::*;
    let mut cmd = 0b100000;

    // Only 4bit interface is supported at the moment
    cmd |= 0                 << 4;
    cmd |= (two_lines as u8) << 3;
    cmd |= match font {
      Font5x8  => 0,
      Font5x10 => 1,
    }                        << 2;

    self.instruction(cmd);
  }

  /// Set the curent read/write data address to the Character Generator RAM
  /// offset `addr`
  fn cgram_address_set(&self, addr: u8) {
    let mut cmd = 0b1000000;

    cmd |= addr & 0b111111;

    self.instruction(cmd);
  }

  /// Set the curent read/write data address to the Display Data RAM offset
  /// `addr`
  fn ddram_address_set(&self, addr: u8) {
    let mut cmd = 0b10000000;

    cmd |= addr & 0b1111111;

    self.instruction(cmd);
  }

  /// Create custom 5x8 char at index `pos` from `bitmap`. Only the 5LSBs of
  /// each bitmap lines are used. There can be only 8 custom 5x8 chars so pos
  /// must be in the range 0 ... 7.
  ///
  /// This resets the cursor positon to 0.
  pub fn custom_char_5x8(&self, pos: u8, bitmap: [ u8, ..8 ]) {
    if pos > 7 {
      panic!("Invalid character position");
    }

    self.cgram_address_set(pos << 3);

    for b in bitmap.iter() {
      self.data(*b & 0b11111);
    }

    // Return the read/write pointer to the Display Data RAM
    self.set_pos(0, 0);
  }

  /// Create custom 5x10 char at index `pos` from `bitmap`. Only the 5LSBs of
  /// each bitmap lines are used. There can be only 8 custom 5x8 chars so pos
  /// must be in the range 0 ... 3.
  pub fn custom_char_5x10(&self, pos: u8, bitmap: [ u8, ..10 ]) {
    if pos > 3 {
      panic!("Invalid character position");
    }

    self.cgram_address_set(pos << 4);

    for b in bitmap.iter() {
      self.data(*b & 0b11111);
    }

    // Return the read/write pointer to the Display Data RAM
    self.set_pos(0, 0);
  }

  /// Send a 8bit command code
  fn instruction(&self, cmd: u8) {
    self.rs.set_low();

    self.write_nibble(cmd >> 4);
    self.write_nibble(cmd);
    // Commands take *at least* 37us to execute, so default to that. If the
    // current instruction needs to delay for more than that the calling
    // function will wait some more.
    self.timer.wait_us(40);
  }

  /// Send 8bit of data
  fn data(&self, data: u8) {
    self.rs.set_high();

    self.write_nibble(data >> 4);
    self.write_nibble(data);
    // Data access take 37us
    self.timer.wait_us(40);
  }

  /// Write a 4bit value to the parallel interface.
  fn write_nibble(&self, v: u8) {
    // Set the 4 data lines in the parallel interface
    match v & 1 {
      0 => self.data[0].set_low(),
      _ => self.data[0].set_high(),
    }

    match v & 2 {
      0 => self.data[1].set_low(),
      _ => self.data[1].set_high(),
    }

    match v & 4 {
      0 => self.data[2].set_low(),
      _ => self.data[2].set_high(),
    }

    match v & 8 {
      0 => self.data[3].set_low(),
      _ => self.data[3].set_high(),
    }

    // Pulse the EN wire to notify the controller.
    self.en.set_high();
    // We need to assert EN for at least 450ns
    self.timer.wait_us(1);
    self.en.set_low();
  }
}

impl<'a> CharIO for Hd44780u<'a> {
  fn putc(&self, value: char) {
    self.data(value as u8);
  }
}
<commit_msg>Fix in lcd hd44780 driver - RFC 248<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Lionel Flandrin <lionel@svkt.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Driver for the Hitachi HD44780U LCD driver

use core::prelude::*;

use drivers::chario::CharIO;
use hal::pin::Gpio;
use hal::timer::Timer;

/// HD44780U driver context
pub struct Hd44780u<'a> {
  /// Timer used for protocol delays
  timer: &'a (Timer + 'a),
  /// Register Selector wire
  rs:    &'a (Gpio + 'a),
  /// Enable wire
  en:    &'a (Gpio + 'a),
  /// The 4 data wires. Those must be wired to [d4, d5, d6, d7] in 4bit mode.
  data: [&'a (Gpio + 'a), ..4],
}

/// The controller supports writing in either direction to accomodate various
/// languages.
pub enum MoveDir {
  /// Cursor moves right after write
  Right,
  /// Cursor moves left after write
  Left,
}

/// The controller supports 5x8 and 5x10 dot fonts depending on the LCD used.
pub enum Font {
  /// Use 5x8 dot matrix font
  Font5x8,
  /// Use 5x10 dot matrix font
  Font5x10,
}

impl<'a> Hd44780u<'a> {
  /// Construct an Hd44780u instance
  pub fn new<'a>(timer: &'a (Timer + 'a),
                 rs:    &'a (Gpio  + 'a),
                 en:    &'a (Gpio  + 'a),
                 data: [&'a (Gpio  + 'a), ..4]) -> Hd44780u<'a> {
    Hd44780u { timer: timer, rs: rs, en: en, data: data }
  }

  /// Power up sequence for 4bit mode as detailed in page 46 of the datasheet.
  /// The two_lines and font parameters are used to set the LCD parameters. See
  /// `function_set` for more details.
  pub fn init(&self, two_lines: bool, font: Font) {
    // Start by pulling RS and EN low
    self.rs.set_low();
    self.en.set_low();

    // We need to wait at least 40ms after the chip is powered before we can
    // talk to it. Assume that the power just went on and wait.
    self.timer.wait_ms(50);

    // Set interface to 8bit
    self.write_nibble(0b0011);

    // Wait 4.1ms
    self.timer.wait_us(4100);

    // Set interface to 8bit
    self.write_nibble(0b0011);

    // Wait 100us
    self.timer.wait_us(100);

    // Set interface to 8bit (for the last time...)
    self.write_nibble(0b0011);
    self.timer.wait_us(100);

    // We can now finally switch to 4bit
    self.write_nibble(0b0010);
    self.timer.wait_us(100);

    // Set function
    self.function_set(two_lines, font);

    self.display_control(true, false, false);

    self.clear();

    // Set default mode
    self.mode_set(MoveDir::Right, false);
  }

  /// Set cursor position to (`col`, `row`). (0, 0) is the top left.
  pub fn set_pos(&self, col: u8, row: u8) {
    // Rows are not continuous in DDRAM, there's a 0x40 offset between the
    // begining of each line.
    self.ddram_address_set(row * 0x40 + col);
  }

  /// Clear the entire display
  pub fn clear(&self) {
    self.instruction(0b0001);
    // I can't find in the datasheet how long this is supposed to take but it
    // seems to take at least a few ms.
    self.timer.wait_ms(5);
  }

  /// Return the cursor to the left of the first line of the display. Also
  /// returns the display to its original status if it was shifted (see
  /// `mode_set`).
  pub fn return_home(&self) {
    self.instruction(0b10);
    // This takes 1.52ms
    self.timer.wait_ms(2);
  }

  /// Set the writing direction and optional display shifting.
  ///
  /// If `shift_display` is true then when writing the cursor remains at the
  /// same place on the display and "pushes" existing data in the direction
  /// specified by dir.
  ///
  /// Calling `clear` resets the writing direction Right but does not change
  /// the display shift setting.
  pub fn mode_set(&self, dir: MoveDir, shift_display: bool) {
    let mut cmd = 0b100;

    let d = match dir {
      MoveDir::Right => 1,
      MoveDir::Left  => 0,
    };

    cmd |= d                     << 1;
    cmd |= (shift_display as u8) << 0;

    self.instruction(cmd);
  }

  /// Display control. If `on` is false nothing is displayed but the screen's
  /// contents remain in RAM and can be re-displayed at any moment. This
  /// function can also enable or disable the cursor and blinking.
  pub fn display_control(&self, on: bool, cursor: bool, blink: bool) {
    let mut cmd = 0b1000;

    cmd |= (on     as u8) << 2;
    cmd |= (cursor as u8) << 1;
    cmd |= (blink  as u8) << 0;

    self.instruction(cmd);
  }

  /// Shift cursor or display in a given direction
  pub fn shift(&self, dir: MoveDir, shift_display: bool) {
    let mut cmd = 0b10000;

    let d = match dir {
      MoveDir::Right => 1,
      MoveDir::Left  => 0,
    };

    cmd |= (shift_display as u8) << 3;
    cmd |= d                     << 2;

    self.instruction(cmd);
  }

  /// Set the bus width, number of lines and character font size. This function
  /// can only be called once in the init sequence.
  ///
  /// Only 4bit wide interfaces are supported for now.
  ///
  /// `two_lines` should be
  /// `false` if the display only has one line, true otherwise.
  ///
  /// If each display character is a matrix of 5x10 dots `char_5x10` should be
  /// `true`. If it's 5x8 dots set it to `false`.
  fn function_set(&self, two_lines: bool, font: Font) {
    use self::Font::*;
    let mut cmd = 0b100000;

    // Only 4bit interface is supported at the moment
    cmd |= 0                 << 4;
    cmd |= (two_lines as u8) << 3;
    cmd |= match font {
      Font5x8  => 0,
      Font5x10 => 1,
    }                        << 2;

    self.instruction(cmd);
  }

  /// Set the curent read/write data address to the Character Generator RAM
  /// offset `addr`
  fn cgram_address_set(&self, addr: u8) {
    let mut cmd = 0b1000000;

    cmd |= addr & 0b111111;

    self.instruction(cmd);
  }

  /// Set the curent read/write data address to the Display Data RAM offset
  /// `addr`
  fn ddram_address_set(&self, addr: u8) {
    let mut cmd = 0b10000000;

    cmd |= addr & 0b1111111;

    self.instruction(cmd);
  }

  /// Create custom 5x8 char at index `pos` from `bitmap`. Only the 5LSBs of
  /// each bitmap lines are used. There can be only 8 custom 5x8 chars so pos
  /// must be in the range 0 ... 7.
  ///
  /// This resets the cursor positon to 0.
  pub fn custom_char_5x8(&self, pos: u8, bitmap: [ u8, ..8 ]) {
    if pos > 7 {
      panic!("Invalid character position");
    }

    self.cgram_address_set(pos << 3);

    for b in bitmap.iter() {
      self.data(*b & 0b11111);
    }

    // Return the read/write pointer to the Display Data RAM
    self.set_pos(0, 0);
  }

  /// Create custom 5x10 char at index `pos` from `bitmap`. Only the 5LSBs of
  /// each bitmap lines are used. There can be only 8 custom 5x8 chars so pos
  /// must be in the range 0 ... 3.
  pub fn custom_char_5x10(&self, pos: u8, bitmap: [ u8, ..10 ]) {
    if pos > 3 {
      panic!("Invalid character position");
    }

    self.cgram_address_set(pos << 4);

    for b in bitmap.iter() {
      self.data(*b & 0b11111);
    }

    // Return the read/write pointer to the Display Data RAM
    self.set_pos(0, 0);
  }

  /// Send a 8bit command code
  fn instruction(&self, cmd: u8) {
    self.rs.set_low();

    self.write_nibble(cmd >> 4);
    self.write_nibble(cmd);
    // Commands take *at least* 37us to execute, so default to that. If the
    // current instruction needs to delay for more than that the calling
    // function will wait some more.
    self.timer.wait_us(40);
  }

  /// Send 8bit of data
  fn data(&self, data: u8) {
    self.rs.set_high();

    self.write_nibble(data >> 4);
    self.write_nibble(data);
    // Data access take 37us
    self.timer.wait_us(40);
  }

  /// Write a 4bit value to the parallel interface.
  fn write_nibble(&self, v: u8) {
    // Set the 4 data lines in the parallel interface
    match v & 1 {
      0 => self.data[0].set_low(),
      _ => self.data[0].set_high(),
    }

    match v & 2 {
      0 => self.data[1].set_low(),
      _ => self.data[1].set_high(),
    }

    match v & 4 {
      0 => self.data[2].set_low(),
      _ => self.data[2].set_high(),
    }

    match v & 8 {
      0 => self.data[3].set_low(),
      _ => self.data[3].set_high(),
    }

    // Pulse the EN wire to notify the controller.
    self.en.set_high();
    // We need to assert EN for at least 450ns
    self.timer.wait_us(1);
    self.en.set_low();
  }
}

impl<'a> CharIO for Hd44780u<'a> {
  fn putc(&self, value: char) {
    self.data(value as u8);
  }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::ty;
use rustc::hir::*;
use utils::{snippet_opt, span_lint_and_then, is_adjusted};

#[allow(missing_copy_implementations)]
pub struct EtaPass;

/// **What it does:** This lint checks for closures which just call another function where the
/// function can be called directly. `unsafe` functions or calls where types get adjusted are
/// ignored.
///
/// **Why is this bad?** Needlessly creating a closure just costs heap space and adds code for no
/// benefit.
///
/// **Known problems:** None
///
/// **Example:** `xs.map(|x| foo(x))` where `foo(_)` is a plain function that takes the exact
/// argument type of `x`.
declare_lint! {
    pub REDUNDANT_CLOSURE, Warn,
    "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)"
}

impl LintPass for EtaPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(REDUNDANT_CLOSURE)
    }
}

impl LateLintPass for EtaPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        match expr.node {
            ExprCall(_, ref args) |
            ExprMethodCall(_, _, ref args) => {
                for arg in args {
                    check_closure(cx, arg)
                }
            }
            _ => (),
        }
    }
}

fn check_closure(cx: &LateContext, expr: &Expr) {
    if let ExprClosure(_, ref decl, ref blk, _) = expr.node {
        if !blk.stmts.is_empty() {
            // || {foo(); bar()}; can't be reduced here
            return;
        }

        if let Some(ref ex) = blk.expr {
            if let ExprCall(ref caller, ref args) = ex.node {
                if args.len() != decl.inputs.len() {
                    // Not the same number of arguments, there
                    // is no way the closure is the same as the function
                    return;
                }
                if is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)) {
                    // Are the expression or the arguments type-adjusted? Then we need the closure
                    return;
                }
                let fn_ty = cx.tcx.expr_ty(caller);
                match fn_ty.sty {
                    // Is it an unsafe function? They don't implement the closure traits
                    ty::TyFnDef(_, _, fn_ty) |
                    ty::TyFnPtr(fn_ty) => {
                        if fn_ty.unsafety == Unsafety::Unsafe ||
                           fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging {
                            return;
                        }
                    }
                    _ => (),
                }
                for (ref a1, ref a2) in decl.inputs.iter().zip(args) {
                    if let PatKind::Binding(_, ident, _) = a1.pat.node {
                        // XXXManishearth Should I be checking the binding mode here?
                        if let ExprPath(None, ref p) = a2.node {
                            if p.segments.len() != 1 {
                                // If it's a proper path, it can't be a local variable
                                return;
                            }
                            if p.segments[0].name != ident.node {
                                // The two idents should be the same
                                return;
                            }
                        } else {
                            return;
                        }
                    } else {
                        return;
                    }
                }
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    if let Some(snippet) = snippet_opt(cx, caller.span) {
                        db.span_suggestion(expr.span, "remove closure as shown:", snippet);
                    }
                });
            }
        }
    }
}
<commit_msg>redundant closures don't allocate<commit_after>use rustc::lint::*;
use rustc::ty;
use rustc::hir::*;
use utils::{snippet_opt, span_lint_and_then, is_adjusted};

#[allow(missing_copy_implementations)]
pub struct EtaPass;

/// **What it does:** This lint checks for closures which just call another function where the
/// function can be called directly. `unsafe` functions or calls where types get adjusted are
/// ignored.
///
/// **Why is this bad?** Needlessly creating a closure adds code for no
/// benefit and gives the optimizer more work.
///
/// **Known problems:** None
///
/// **Example:** `xs.map(|x| foo(x))` where `foo(_)` is a plain function that takes the exact
/// argument type of `x`.
declare_lint! {
    pub REDUNDANT_CLOSURE, Warn,
    "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)"
}

impl LintPass for EtaPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(REDUNDANT_CLOSURE)
    }
}

impl LateLintPass for EtaPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        match expr.node {
            ExprCall(_, ref args) |
            ExprMethodCall(_, _, ref args) => {
                for arg in args {
                    check_closure(cx, arg)
                }
            }
            _ => (),
        }
    }
}

fn check_closure(cx: &LateContext, expr: &Expr) {
    if let ExprClosure(_, ref decl, ref blk, _) = expr.node {
        if !blk.stmts.is_empty() {
            // || {foo(); bar()}; can't be reduced here
            return;
        }

        if let Some(ref ex) = blk.expr {
            if let ExprCall(ref caller, ref args) = ex.node {
                if args.len() != decl.inputs.len() {
                    // Not the same number of arguments, there
                    // is no way the closure is the same as the function
                    return;
                }
                if is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)) {
                    // Are the expression or the arguments type-adjusted? Then we need the closure
                    return;
                }
                let fn_ty = cx.tcx.expr_ty(caller);
                match fn_ty.sty {
                    // Is it an unsafe function? They don't implement the closure traits
                    ty::TyFnDef(_, _, fn_ty) |
                    ty::TyFnPtr(fn_ty) => {
                        if fn_ty.unsafety == Unsafety::Unsafe ||
                           fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging {
                            return;
                        }
                    }
                    _ => (),
                }
                for (ref a1, ref a2) in decl.inputs.iter().zip(args) {
                    if let PatKind::Binding(_, ident, _) = a1.pat.node {
                        // XXXManishearth Should I be checking the binding mode here?
                        if let ExprPath(None, ref p) = a2.node {
                            if p.segments.len() != 1 {
                                // If it's a proper path, it can't be a local variable
                                return;
                            }
                            if p.segments[0].name != ident.node {
                                // The two idents should be the same
                                return;
                            }
                        } else {
                            return;
                        }
                    } else {
                        return;
                    }
                }
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    if let Some(snippet) = snippet_opt(cx, caller.span) {
                        db.span_suggestion(expr.span, "remove closure as shown:", snippet);
                    }
                });
            }
        }
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/24_game
// with a recursive descent parser for a simple calculator (+ - * /)
// using the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// It follows operator precedence (i.e. 2 + 3 * 3 = 11),
// understands negation (-5 + 6 = 1), ignores whitespace
// and allows the use of parentheses

#![feature(macro_rules)]
use std::char::to_digit;

#[cfg(not(test))]
use std::rand::{task_rng, sample};
#[cfg(not(test))]
use std::io::stdio::stdin;
#[cfg(not(test))]
use std::io::BufferedReader;

#[cfg(not(test))]
fn main() {
    let mut rng=task_rng();
    let mut input = BufferedReader::new(stdin());
    loop {
        let mut sample = sample(&mut rng, range(1u, 10), 4);

        println!("make 24 by combining the following 4 numbers with + - * / or (q)uit");
        println!("{}", sample);

        let line = input.read_line().unwrap();
        match line.as_slice().trim() {
            "q" => break,
            input if check_values(sample.as_mut_slice(), input) => {
                    let mut p = Parser :: new(input);
                    match p.parse() {
                        Ok(i) if i==24f32 => println!("you made it!"),
                        Ok(i) => println!("you entered {}, try again!", i),
                        Err(s)  => println!("{}",s)
                    };
                }
            _ => println!("unrecognized input, try again")
        }
    }
}

// check that the entered expression uses the random values
// that have been proposed
fn check_values(sample:&mut [uint], input:&str) -> bool {
    let lex=Lexer::new(input);

    let mut numbers_used : Vec<uint> = lex.filter_map(|a| match a {
                                                        Int(i)  => Some(i),
                                                        _       => None
                                                    }).collect();
    numbers_used.sort();
    sample.sort();
    numbers_used.as_slice() == sample
}

// the tokens that our parser is going to recognize
#[deriving(PartialEq,Eq,Show)]
enum Token {LParen, RParen, Plus, Minus, Slash, Star, Int(uint)}

impl Token {
   // are tokens associated to a binary operation?
   fn is_binary(&self) -> bool {
        match self {
            &Plus | &Minus | &Slash | &Star => true,
            _ => false
        }
    }
}

#[inline]
// map a character to its corresponding token
fn single_char_to_token(ch:Option<char>) -> Option<Token> {
    match ch {
            Some('(') => Some(LParen),
            Some(')') => Some(RParen),
            Some('+') => Some(Plus),
            Some('-') => Some(Minus),
            Some('/') => Some(Slash),
            Some('*') => Some(Star),
            _         => None
    }
}

// Lexer reads an expression like (a + b) / c * d
// as an iterator on the tokens that compose it
// Int(a), LParen, Plus, Int(b), RParen...
struct Lexer<'a> {
    input_str:  &'a str,
    position:   uint
}

impl <'a> Lexer<'a> {
    fn new(input_str: &'a str) -> Lexer<'a> {
        Lexer { input_str: input_str, position: 0u }
    }

    fn expect(&mut self, expected:&[Token]) -> Result<Token, String> {
        let n = self.position;
        match self.next() {
            Some(a) if expected.contains(&a)  => Ok(a),
            other  => Err(format!("Parsing error: {} was unexpected at position {}", other, n))
        }
    }
}

impl <'a> Iterator<Token> for Lexer<'a> {
    fn next(&mut self) -> Option<Token> {
        let remaining_input=self.input_str.slice_from(self.position);
        let ch_iter=remaining_input.chars();

        // skip spaces and update position
        let mut spaces=ch_iter.take_while(|ch| ch.is_whitespace());
        let n_spaces=spaces.count();
        self.position+=n_spaces;
        let mut trimmed=ch_iter.skip(n_spaces);

        // read digits (note: not checking length, risks overflowing uint)
        let digits=trimmed.take_while(|d| d.is_digit());
        // transform char digits to a uint and update position
        let val=digits.map(|c| to_digit(c, 10).unwrap())
            .fold(0u, |a, b| {
                self.position+=1;
                b + a * 10
            });

        let ret = if val > 0 {
            Some(Int(val))
        } else {
            // not a value. Read other tokens
            let cur=trimmed.next();
            self.position +=1;
            single_char_to_token(cur)
        };
        ret
    }
}

// operators are a "higher level" concept than tokens
// as they define the semantics of the expression language
// e.g. token "Minus" can correspond to the unary Neg Operator (-a)
// or to the binary Sub operator (a - b)
#[deriving(PartialEq,Eq)]
enum Operator {Neg, Add, Sub, Mul, Div, Sentinel}

#[deriving(PartialEq,Eq)]
struct OperatorPrecedence(Operator);

impl Operator {
     fn precedence(self) -> OperatorPrecedence  {
        OperatorPrecedence(self)
    }
}

impl OperatorPrecedence {
    fn prec(self) -> uint {
        match self {
            OperatorPrecedence(Sentinel) => 0u,
            OperatorPrecedence(Add) | OperatorPrecedence(Sub) => 1u,
            OperatorPrecedence(Neg)        => 2u,
            OperatorPrecedence(Mul) | OperatorPrecedence(Div) => 3u
        }
    }
}

/*
    Operator precedence for binary operators:
    * if x has higher precedence than y precedence for x > precedence for y
    * if x and y have equal precedence the first one has precedence
    e.g. in expression (4 / 2 * 2) operators * and / have the same precedence,
    but the operations must be performed in the order they appear
    (division first, multiplication second) otherwise results are different
*/
impl PartialOrd for OperatorPrecedence {
    fn lt(&self, other: &OperatorPrecedence) -> bool {
        match (self, other) {
            (&OperatorPrecedence(Mul), &OperatorPrecedence(Div)) => false,
            (&OperatorPrecedence(Div), &OperatorPrecedence(Mul)) => false,
            (&OperatorPrecedence(Add), &OperatorPrecedence(Sub)) => false,
            (&OperatorPrecedence(Sub), &OperatorPrecedence(Add)) => false,
            _  => self.prec() < other.prec()
        }
    }

    fn gt(&self, other: &OperatorPrecedence) -> bool {
        match (self, other) {
            (&OperatorPrecedence(Mul), &OperatorPrecedence(Div)) => true,
            (&OperatorPrecedence(Div), &OperatorPrecedence(Mul)) => true,
            (&OperatorPrecedence(Add), &OperatorPrecedence(Sub)) => true,
            (&OperatorPrecedence(Sub), &OperatorPrecedence(Add)) => true,
            _          => self.prec() > other.prec()
        }
    }
}

// recursive descent parser
// with the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// I followed the names of the methods as closely as possible vs the pseudo-code
// that illustrates the algorithm
struct Parser<'a> {
    operators: Vec<Operator>,
    operands:  Vec<f32>,
    lexer:     Lexer<'a>
}

impl <'a> Parser<'a> {
    fn new(input_str: &'a str) -> Parser<'a> {
        Parser {
            operators:  Vec::new(),
            operands:   Vec::new(),
            lexer:      Lexer::new(input_str)
        }
    }

    fn parse(&mut self) -> Result<f32, String> {
        self.operators.push(Sentinel);
        try!(self.e());
        let res=self.operands.last();
        let ret=match res {
            Some(&r) => Ok(r),
            None    => Err("something went wrong, got no result".to_string())
        };
        ret
    }

    fn e(&mut self) -> Result<(), String> {
        try!(self.p());

        let mut n=self.lexer.next();

        while n.is_some() && n.unwrap().is_binary() {
            match n {
                Some(Plus) => self.push_operator(Add),
                Some(Minus) => self.push_operator(Sub),
                Some(Star) => self.push_operator(Mul),
                Some(Slash) => self.push_operator(Div),
                _ => unreachable!() //shouldn't get there (there are no other
                                    // binary operators
            };
            try!(self.p());

            let mut n_peek = self.lexer.peekable();
            if n_peek.peek().is_none() || !n_peek.peek().unwrap().is_binary() { break; }
            n = self.lexer.next();
        }
        while self.operators.last().is_some() && self.operators.last().unwrap() != &Sentinel {
            self.pop_operator();
        }
        Ok(())
    }

    fn p(&mut self) -> Result<(), String> {
        match self.lexer.next() {
            Some(Int(n)) => {
                self.operands.push(n as f32);
            },
            Some(LParen) => {
                self.operators.push(Sentinel);
                try!(self.e());
                try!(self.lexer.expect(&[RParen]));
                self.operators.pop();
            },
            Some(Minus) => {
                self.push_operator(Neg);
                try!(self.p());
            },
            Some(e) => return Err(format!("unexpected token {}", e)),
            _       => return Err("unexpected end of command".to_string())
            //Some(Minus) =>
        }
        Ok(())
    }

    fn pop_operator(&mut self) {
        match self.operators.pop() {
            Some(Add) => self.binary_op(|t1,t2| t1+t2),
            Some(Sub) => self.binary_op(|t1,t2| t1-t2),
            Some(Mul) => self.binary_op(|t1,t2| t1*t2),
            Some(Div) => self.binary_op(|t1,t2| t1/t2),
            Some(Neg) => self.unary_op(|t1| -t1),
            _         => unreachable!()
            }
    }

    fn push_operator(&mut self, op:Operator) {
        match self.operators.last() {
            Some(&a) if a.precedence() > op.precedence() => self.pop_operator(),
            _ => ()
        }
        self.operators.push(op);
    }

    #[inline]
    fn binary_op(&mut self, op:|f32,f32| -> f32) {
        let t1=self.operands.pop().unwrap();
        let t2=self.operands.pop().unwrap();
        self.operands.push(op(t2,t1));
    }

    #[inline]
    fn unary_op(&mut self, op:|f32| -> f32) {
        let t1=self.operands.pop().unwrap();
        self.operands.push(op(t1));
    }
}

#[test]
fn test_precedence() {
    assert!(Mul.precedence() > Add.precedence());
    assert!(Mul.precedence() > Div.precedence());
    assert!((Mul.precedence() < Div.precedence())==false);
}

#[test]
fn lexer_iter() {
    // test read token and character's position in the iterator
    macro_rules! test_tok( ($tok:ident, $exp_tok:expr, $exp_pos:expr) =>
        ( assert_eq!(($tok.next(), $tok.position), (Some($exp_tok), $exp_pos));))

    let mut tok=Lexer::new("  15 + 4");
    test_tok!(tok, Int(15), 4);
    test_tok!(tok, Plus, 6);
    let read=tok.expect(&[LParen,Int(4),RParen]);
    assert_eq!(read, Ok(Int(4)));

    let mut tok=Lexer::new("");
    assert_eq!(tok.next(), None);

    let mut tok=Lexer::new("     ");
    assert_eq!(tok.next(), None);

    let mut tok=Lexer::new("2 * (3+4/2)");
    test_tok!(tok, Int(2), 1);
    test_tok!(tok, Star, 3);
    test_tok!(tok, LParen, 5);
    test_tok!(tok, Int(3), 6);
    test_tok!(tok, Plus, 7);
    test_tok!(tok, Int(4), 8);
    test_tok!(tok, Slash, 9);
    test_tok!(tok, Int(2), 10);
    test_tok!(tok, RParen, 11);
}

#[test]
fn parse()
{
    assert_eq!(Parser::new("2+2").parse(), Ok(4f32));
    assert_eq!(Parser::new("2+3*4").parse(), Ok(14f32));
    assert_eq!(Parser::new("4*(3+2)").parse(), Ok(20f32));
    assert_eq!(Parser::new("5/(3+2)*3").parse(), Ok(3f32));
    assert_eq!(Parser::new("2++12").parse(), Err("unexpected token Plus".to_string()));
    assert_eq!(Parser::new("-2+12").parse(), Ok(10f32));
    assert_eq!(Parser::new("-2*(2+3)").parse(), Ok(-10f32));
}

#[test]
fn try_check_values() {
    let m = &mut [1,2,3,4];
    assert!(check_values(m, "1+3 -(4/2)"));
}
<commit_msg>refactorings on 24 game<commit_after>// Implements http://rosettacode.org/wiki/24_game
// with a recursive descent parser for a simple calculator (+ - * /)
// using the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// It follows operator precedence (i.e. 2 + 3 * 3 = 11),
// understands negation (-5 + 6 = 1), ignores whitespace
// and allows the use of parentheses

#![feature(macro_rules)]
use std::char::to_digit;

#[cfg(not(test))]
use std::rand;

#[cfg(not(test))]
fn main() {
    let mut rng=rand::task_rng();
    let mut input = std::io::stdin();

    loop {
        let mut sample = rand::sample(&mut rng, range(1u, 10), 4);

        println!("make 24 by combining the following 4 numbers with + - * / or (q)uit");
        println!("{}", sample);

        let line = input.read_line().unwrap();
        match line.as_slice().trim() {
            "q" => break,
            input if check_values(sample.as_mut_slice(), input) => {
                    let mut p = Parser :: new(input);
                    match p.parse() {
                        Ok(i) if i==24f32 => println!("you made it!"),
                        Ok(i) => println!("you entered {}, try again!", i),
                        Err(s)  => println!("{}",s)
                    };
                }
            _ => println!("unrecognized input, try again")
        }
    }
}

// Returns true if the entered expression uses the values contained in sample
fn check_values(sample:&mut [uint], input:&str) -> bool {
    let lex=Lexer::new(input);

    let mut numbers_used : Vec<uint> = lex.filter_map(|a| match a {
                                                        Int(i)  => Some(i),
                                                        _       => None
                                                    }).collect();
    numbers_used.sort();
    sample.sort();
    numbers_used.as_slice() == sample
}

// the tokens that our parser is going to recognize
#[deriving(PartialEq,Eq,Show)]
enum Token {LParen, RParen, Plus, Minus, Slash, Star, Int(uint)}

impl Token {
   // are tokens associated to a binary operation?
   fn is_binary(&self) -> bool {
        match self {
            &Plus | &Minus | &Slash | &Star => true,
            _ => false
        }
    }
}

#[inline]
// map a character to its corresponding token
fn single_char_to_token(ch:Option<char>) -> Option<Token> {
    match ch {
            Some('(') => Some(LParen),
            Some(')') => Some(RParen),
            Some('+') => Some(Plus),
            Some('-') => Some(Minus),
            Some('/') => Some(Slash),
            Some('*') => Some(Star),
            _         => None
    }
}

// Lexer reads an expression like (a + b) / c * d
// as an iterator on the tokens that compose it
// Int(a), LParen, Plus, Int(b), RParen...
struct Lexer<'a> {
    input_str:  &'a str,
    position:   uint
}

impl <'a> Lexer<'a> {
    fn new(input_str: &'a str) -> Lexer<'a> {
        Lexer { input_str: input_str, position: 0u }
    }

    fn expect(&mut self, expected:&[Token]) -> Result<Token, String> {
        let n = self.position;
        match self.next() {
            Some(a) if expected.contains(&a)  => Ok(a),
            other  => Err(format!("Parsing error: {} was unexpected at position {}", other, n))
        }
    }
}

impl <'a> Iterator<Token> for Lexer<'a> {
    fn next(&mut self) -> Option<Token> {
        let remaining_input=self.input_str.slice_from(self.position);
        let ch_iter=remaining_input.chars();

        // skip spaces and update position
        let mut spaces=ch_iter.take_while(|ch| ch.is_whitespace());
        let n_spaces=spaces.count();
        self.position+=n_spaces;
        let mut trimmed=ch_iter.skip(n_spaces);

        // read digits (note: not checking length, risks overflowing uint)
        let digits=trimmed.take_while(|d| d.is_digit());
        // transform char digits to a uint and update position
        let val=digits.map(|c| to_digit(c, 10).unwrap())
            .fold(0u, |a, b| {
                self.position+=1;
                b + a * 10
            });

        let ret = if val > 0 {
            Some(Int(val))
        } else {
            // not a value. Read other tokens
            let cur=trimmed.next();
            self.position +=1;
            single_char_to_token(cur)
        };
        ret
    }
}

// operators are a "higher level" concept than tokens
// as they define the semantics of the expression language
// e.g. token "Minus" can correspond to the unary Neg Operator (-a)
// or to the binary Sub operator (a - b)
#[deriving(PartialEq,Eq)]
enum Operator {Neg, Add, Sub, Mul, Div, Sentinel}

#[deriving(PartialEq,Eq)]
struct OperatorPrecedence(Operator);

impl Operator {
     fn precedence(self) -> OperatorPrecedence  {
        OperatorPrecedence(self)
    }
}

impl OperatorPrecedence {
    fn prec(self) -> uint {
        match self {
            OperatorPrecedence(Sentinel) => 0u,
            OperatorPrecedence(Add) | OperatorPrecedence(Sub) => 1u,
            OperatorPrecedence(Neg)        => 2u,
            OperatorPrecedence(Mul) | OperatorPrecedence(Div) => 3u
        }
    }
}

/*
    Operator precedence for binary operators:
    * if x has higher precedence than y precedence for x > precedence for y
    * if x and y have equal precedence the first one has precedence
    e.g. in expression (4 / 2 * 2) operators * and / have the same precedence,
    but the operations must be performed in the order they appear
    (division first, multiplication second) otherwise results are different
*/
impl PartialOrd for OperatorPrecedence {
    fn lt(&self, other: &OperatorPrecedence) -> bool {
        match (self, other) {
            (&OperatorPrecedence(Mul), &OperatorPrecedence(Div)) => false,
            (&OperatorPrecedence(Div), &OperatorPrecedence(Mul)) => false,
            (&OperatorPrecedence(Add), &OperatorPrecedence(Sub)) => false,
            (&OperatorPrecedence(Sub), &OperatorPrecedence(Add)) => false,
            _  => self.prec() < other.prec()
        }
    }

    fn gt(&self, other: &OperatorPrecedence) -> bool {
        match (self, other) {
            (&OperatorPrecedence(Mul), &OperatorPrecedence(Div)) => true,
            (&OperatorPrecedence(Div), &OperatorPrecedence(Mul)) => true,
            (&OperatorPrecedence(Add), &OperatorPrecedence(Sub)) => true,
            (&OperatorPrecedence(Sub), &OperatorPrecedence(Add)) => true,
            _          => self.prec() > other.prec()
        }
    }
}

// recursive descent parser
// with the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// I followed the names of the methods as closely as possible vs the pseudo-code
// that illustrates the algorithm
struct Parser<'a> {
    operators: Vec<Operator>,
    operands:  Vec<f32>,
    lexer:     Lexer<'a>
}

impl <'a> Parser<'a> {
    fn new(input_str: &'a str) -> Parser<'a> {
        Parser {
            operators:  Vec::new(),
            operands:   Vec::new(),
            lexer:      Lexer::new(input_str)
        }
    }

    fn parse(&mut self) -> Result<f32, String> {
        self.operators.push(Sentinel);
        try!(self.e());
        let res=self.operands.last();
        let ret=match res {
            Some(&r) => Ok(r),
            None    => Err("something went wrong, got no result".to_string())
        };
        ret
    }

    fn e(&mut self) -> Result<(), String> {
        try!(self.p());

        let mut n=self.lexer.next();

        while n.is_some() && n.unwrap().is_binary() {
            match n {
                Some(Plus) => self.push_operator(Add),
                Some(Minus) => self.push_operator(Sub),
                Some(Star) => self.push_operator(Mul),
                Some(Slash) => self.push_operator(Div),
                _ => unreachable!() //shouldn't get there (there are no other
                                    // binary operators
            };
            try!(self.p());

            let mut n_peek = self.lexer.peekable();
            if n_peek.peek().is_none() || !n_peek.peek().unwrap().is_binary() { break; }
            n = self.lexer.next();
        }
        while self.operators.last().is_some() && self.operators.last().unwrap() != &Sentinel {
            self.pop_operator();
        }
        Ok(())
    }

    fn p(&mut self) -> Result<(), String> {
        match self.lexer.next() {
            Some(Int(n)) => {
                self.operands.push(n as f32);
            },
            Some(LParen) => {
                self.operators.push(Sentinel);
                try!(self.e());
                try!(self.lexer.expect(&[RParen]));
                self.operators.pop();
            },
            Some(Minus) => {
                self.push_operator(Neg);
                try!(self.p());
            },
            Some(e) => return Err(format!("unexpected token {}", e)),
            _       => return Err("unexpected end of command".to_string())
            //Some(Minus) =>
        }
        Ok(())
    }

    fn pop_operator(&mut self) {
        match self.operators.pop() {
            Some(Add) => self.binary_op(|t1,t2| t1+t2),
            Some(Sub) => self.binary_op(|t1,t2| t1-t2),
            Some(Mul) => self.binary_op(|t1,t2| t1*t2),
            Some(Div) => self.binary_op(|t1,t2| t1/t2),
            Some(Neg) => self.unary_op(|t1| -t1),
            _         => unreachable!()
            }
    }

    fn push_operator(&mut self, op:Operator) {
        match self.operators.last() {
            Some(&a) if a.precedence() > op.precedence() => self.pop_operator(),
            _ => ()
        }
        self.operators.push(op);
    }

    #[inline]
    fn binary_op(&mut self, op:|f32,f32| -> f32) {
        let t1=self.operands.pop().unwrap();
        let t2=self.operands.pop().unwrap();
        self.operands.push(op(t2,t1));
    }

    #[inline]
    fn unary_op(&mut self, op:|f32| -> f32) {
        let t1=self.operands.pop().unwrap();
        self.operands.push(op(t1));
    }
}

#[test]
fn test_precedence() {
    assert!(Mul.precedence() > Add.precedence());
    assert!(Mul.precedence() > Div.precedence());
    assert!((Mul.precedence() < Div.precedence())==false);
}

#[test]
fn lexer_iter() {
    // test read token and character's position in the iterator
    macro_rules! test_tok( ($tok:ident, $exp_tok:expr, $exp_pos:expr) =>
        ( assert_eq!(($tok.next(), $tok.position), (Some($exp_tok), $exp_pos));))

    let mut tok=Lexer::new("  15 + 4");
    test_tok!(tok, Int(15), 4);
    test_tok!(tok, Plus, 6);
    let read=tok.expect(&[LParen,Int(4),RParen]);
    assert_eq!(read, Ok(Int(4)));

    let mut tok=Lexer::new("");
    assert_eq!(tok.next(), None);

    let mut tok=Lexer::new("     ");
    assert_eq!(tok.next(), None);

    let mut tok=Lexer::new("2 * (3+4/2)");
    test_tok!(tok, Int(2), 1);
    test_tok!(tok, Star, 3);
    test_tok!(tok, LParen, 5);
    test_tok!(tok, Int(3), 6);
    test_tok!(tok, Plus, 7);
    test_tok!(tok, Int(4), 8);
    test_tok!(tok, Slash, 9);
    test_tok!(tok, Int(2), 10);
    test_tok!(tok, RParen, 11);
}

#[test]
fn parse()
{
    assert_eq!(Parser::new("2+2").parse(), Ok(4.));
    assert_eq!(Parser::new("2+3*4").parse(), Ok(14.));
    assert_eq!(Parser::new("4*(3+2)").parse(), Ok(20.));
    assert_eq!(Parser::new("5/(3+2)*3").parse(), Ok(3.));
    assert_eq!(Parser::new("2++12").parse(), Err("unexpected token Plus".to_string()));
    assert_eq!(Parser::new("-2+12").parse(), Ok(10.));
    assert_eq!(Parser::new("-2*(2+3)").parse(), Ok(-10.));
}

#[test]
fn try_check_values() {
    let m = &mut [1,2,3,4];
    assert!(check_values(m, "1+3 -(4/2)"));
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![feature(test)]
extern crate test;
extern crate input_stream;
extern crate rand;

use input_stream::InputStream;
use rand::random;
use std::str::FromStr;
use test::Bencher;

const NUMBERS_GENERATED: usize = 100_000;

fn generate_numbers<T>(many: usize) -> String
    where T: rand::Rand + std::fmt::Display
{
    (0..many)
        .map(|_| random::<T>().to_string())
        .fold("".to_string(), |mut str, number| {
            str += " ";
            str += &number;
            str
        })
}

fn count_numbers<T>(input: &str) -> usize
    where T: FromStr,
          <T as FromStr>::Err: std::error::Error + Send + 'static
{
    let mut stream = InputStream::new(input.as_bytes());

    let mut count = 0;
    while let Ok(_) = stream.scan::<T>() {
        count += 1;
    }
    count
}

macro_rules! num_bench {
    ($(($num: ty, $bench: ident)),* ) => {
        $(
            #[bench]
            fn $bench(b: &mut Bencher) {
                let numbers = generate_numbers::<$num>(NUMBERS_GENERATED);

                b.iter(|| {
                    let count = count_numbers::<$num>(&numbers);
                    assert_eq!(count, NUMBERS_GENERATED);
                });
            }
         )*
    }
}

num_bench!{
    (u8, u8_bench),
    (u16, u16_bench),
    (u32, u32_bench),
    (u64, u64_bench),
    (usize, usize_bench),
    (i8, i8_bench),
    (i16, i16_bench),
    (i32, i32_bench),
    (i64, i64_bench),
    (isize, isize_bench),
    (f32, f32_bench),
    (f64, f64_bench)
}
<commit_msg>Cached the random generator so the benchmarks run faster<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![feature(test)]
extern crate test;
extern crate input_stream;
extern crate rand;

use input_stream::InputStream;
use rand::Rng;
use std::str::FromStr;
use test::Bencher;

const NUMBERS_GENERATED: usize = 100_000;

fn generate_numbers<T>(many: usize) -> String
    where T: rand::Rand + std::fmt::Display
{
    let mut rng = rand::thread_rng();
    (0..many)
        .map(|_| rng.gen::<T>().to_string())
        .fold("".to_string(), |mut str, number| {
            str += " ";
            str += &number;
            str
        })
}

fn count_numbers<T>(input: &str) -> usize
    where T: FromStr,
          <T as FromStr>::Err: std::error::Error + Send + 'static
{
    let mut stream = InputStream::new(input.as_bytes());

    let mut count = 0;
    while let Ok(_) = stream.scan::<T>() {
        count += 1;
    }
    count
}

macro_rules! num_bench {
    ($(($num: ty, $bench: ident)),* ) => {
        $(
            #[bench]
            fn $bench(b: &mut Bencher) {
                let numbers = generate_numbers::<$num>(NUMBERS_GENERATED);

                b.iter(|| {
                    let count = count_numbers::<$num>(&numbers);
                    assert_eq!(count, NUMBERS_GENERATED);
                });
            }
         )*
    }
}

num_bench!{
    (u8, u8_bench),
    (u16, u16_bench),
    (u32, u32_bench),
    (u64, u64_bench),
    (usize, usize_bench),
    (i8, i8_bench),
    (i16, i16_bench),
    (i32, i32_bench),
    (i64, i64_bench),
    (isize, isize_bench),
    (f32, f32_bench),
    (f64, f64_bench)
}
<|endoftext|>


<commit_before>use csrf::{AesGcmCsrfProtection, CsrfProtection, CSRF_HEADER};
//use data_encoding::BASE64;

use config::Config;
use controller::context::{RequestContext, ResponseContext};
use controller::middleware::user::user_session;

use std::str;

header! { (XCsrfHeader, CSRF_HEADER) => [String] }

pub fn csrf_protection<F>(mut request: RequestContext, seed: F) -> ResponseContext
    where F: Fn(RequestContext) -> ResponseContext
{
    if let Some(csrf_header) = request.headers.get::<XCsrfHeader>() {
        let &XCsrfHeader(ref csrf) = csrf_header;
        println!("Incoming csrf header: {:?}", csrf);
    }

    if let Some(ref body) = request.body {
        println!("Body with csrf: {:?}", body);
    }

    let (token, cookie) = new_token_pair(None);
    request.csrf_token = Some(token);

    let response = user_session(request, seed);
    response
}

fn new_token_pair(previous_token: Option<&[u8; 64]>) -> (String, String)
{
    let mut key: [u8;32] = Default::default();
    key.copy_from_slice(Config::idem().security.csrf_protection_key.as_bytes());

    let protect = AesGcmCsrfProtection::from_key(key);
    let (token, cookie) = protect.generate_token_pair(previous_token, Config::idem().security.csrf_token_ttl_seconds)
        .expect("couldn't generate token/cookie pair");

    (token.b64_string(), cookie.b64_string())
}<commit_msg>Complete csrf protection<commit_after>use hyper::header::Cookie;
use csrf::{AesGcmCsrfProtection, CsrfProtection, CSRF_HEADER, CSRF_COOKIE_NAME};
use data_encoding::base64;

use config::Config;
use controller::base;
use controller::context::{RequestContext, ResponseContext};
use controller::middleware::user::user_session;

use std::str;

header! { (XCsrfHeader, CSRF_HEADER) => [String] }

pub fn csrf_protection<F>(mut request: RequestContext, seed: F) -> ResponseContext
    where F: Fn(RequestContext) -> ResponseContext
{
    let protect = make_protect();

    if request.is_post() {
        let (token_bytes, cookie_bytes) = parse_token_pair(&request);
        if token_bytes.is_empty() || cookie_bytes.is_empty() {
            println!("ERROR csrf_protection - empty token pair");
            return base::redirect("/error");
        }

        if !verify_token_pair(&protect, &token_bytes, &cookie_bytes) {
            println!("ERROR csrf_protection - token pair is not verified");
            return base::redirect("/error");
        }
    }

    let (token, cookie) = new_token_pair(&protect, None);
    request.csrf_token = Some(token);

    let mut response = user_session(request, seed);
    response.set_cookie(format!("{}={}; Path=/; HttpOnly", CSRF_COOKIE_NAME, cookie));
    response
}

fn make_protect() -> AesGcmCsrfProtection
{
    let mut key: [u8;32] = Default::default();
    key.copy_from_slice(Config::idem().security.csrf_protection_key.as_bytes());

    AesGcmCsrfProtection::from_key(key)
}

fn parse_token_pair(request: &RequestContext) -> (Vec<u8>, Vec<u8>)
{
    let token = if let Some(ref body) = request.body {
        let token = body.get("csrf-token").map(AsRef::as_ref).unwrap_or("");
        println!("Incoming csrf body token: {:?}", token);
        token
    } else if let Some(csrf_header) = request.headers.get::<XCsrfHeader>() {
        // TODO: implement header csrf validation
        let &XCsrfHeader(ref csrf) = csrf_header;
        println!("Incoming csrf header: {:?}", csrf);
        ""
    } else {
        ""
    };

    let cookie = if let Some(ref cookie) = request.headers.get::<Cookie>() {
        let token = cookie.get(CSRF_COOKIE_NAME).unwrap_or("");
        println!("Incoming csrf cookie token: {:?}", token);
        token
    } else {
        ""
    };

    (
        base64::decode(token.as_bytes()).unwrap_or(vec![]),
        base64::decode(cookie.as_bytes()).unwrap_or(vec![])
    )
}

fn verify_token_pair<T>(protect: &T, token_bytes: &[u8], cookie_bytes: &[u8]) -> bool
    where T: CsrfProtection
{
    match protect.parse_token(token_bytes) {
        Ok(parsed_token) => match protect.parse_cookie(cookie_bytes) {
            Ok(parsed_cookie) => {
                protect.verify_token_pair(&parsed_token, &parsed_cookie)
            },
            Err(err) => {
                println!("ERROR verify_token_pair - {:?}", err);
                false
            }
        },
        Err(err) => {
            println!("ERROR verify_token_pair - {:?}", err);
            false
        }
    }
}

fn new_token_pair<T>(protect: &T, previous_token: Option<&[u8; 64]>) -> (String, String)
    where T: CsrfProtection
{
    let ttl = Config::idem().security.csrf_token_ttl_seconds;
    let (token, cookie) = protect.generate_token_pair(previous_token, ttl)
        .expect("couldn't generate token/cookie pair");

    (token.b64_string(), cookie.b64_string())
}<|endoftext|>


<commit_before>use std::ops::Mul;
use std::ops::Add;
use std::ops::Div;

struct Matrix {
	cols: i32,
	rows: i32,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: i32, rows: i32, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: i32, rows: i32) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; (cols*rows) as usize]
        }
    }

    fn identity(size: i32) -> Matrix {
    	let mut data = vec![0.0; (size*size) as usize];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }
}

impl Mul<f32> for Matrix {
	type Output = Matrix;

	fn mul(self, m: f32) -> Matrix {

		for entry in &self.data {
			entry * m;
		}

		return self;
	}
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		return self;
	}
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, m: f32) -> Matrix {
		for entry in &self.data {
			entry + m;
		}

		return self;
	}
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		return self;
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		return self;
	}
}<commit_msg>Fixed basic matrix scalar multiplication.<commit_after>use std::ops::{Mul, Add, Div, Sub, Index};

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = Vec::with_capacity(size * size);

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = Vec::with_capacity(size * size);

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, m: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * m).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		return self;
	}
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, m: f32) -> Matrix {
		for entry in &self.data {
			entry + m;
		}

		return self;
	}
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		return self;
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		return self;
	}
}<|endoftext|>


<commit_before>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod copy;
pub mod trailed;

pub use variable::memory::copy::*;
pub use variable::memory::trailed::*;
<commit_msg>[Test][Restoration] Start tests of restoration strategy. A simple identity test is implemented.<commit_after>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod copy;
pub mod trailed;

pub use variable::memory::copy::*;
pub use variable::memory::trailed::*;

#[cfg(test)]
mod test {
  use super::*;
  use kernel::*;
  use variable::test::DomainI32;
  use variable::concept::*;
  use variable::store::*;
  use variable::ops::*;
  use propagation::events::*;
  use interval::interval::*;
  use gcollections::ops::*;

  pub type StoreI32<M> = Store<M, DomainI32, FDEvent>;

  #[test]
  fn identity_restoration() {
    type MCopy = CopyMemory<DomainI32>;
    type MTrailed = TrailedStore<DomainI32>;
    identity_restoration_mem::<MCopy>();
    identity_restoration_mem::<MTrailed>();
  }

  fn identity_restoration_mem<M>() where
   M: MemoryConcept<DomainI32>
  {
    let domains_set = vec![
      vec![],
      vec![(0,0)],
      vec![(0,10), (5,5)]
    ];

    for domains in domains_set {
      let doms: Vec<_> = domains.into_iter()
        .map(|d| d.to_interval())
        .collect();
      for i in 1..4 {
        identity_restoration_n::<M>(i, doms.clone());
      }
    }
  }

  fn identity_restoration_n<M>(num_labels: usize, domains: Vec<DomainI32>) where
   M: MemoryConcept<DomainI32>
  {
    let mut store: StoreI32<M> = Store::empty();

    for dom in domains.clone() {
      store.alloc(dom);
    }

    let mut frozen = store.freeze();
    let labels: Vec<_> = (0..num_labels)
      .map(|_| frozen.label())
      .collect();

    for label in labels {
      store = frozen.restore(label);

      let store_doms: Vec<_> = store.iter().cloned().collect();
      assert_eq!(domains, store_doms);

      frozen = store.freeze();
    }
  }

}
<|endoftext|>


<commit_before>use raft::SyncServiceClient;
use rpc;
use super::*;
use super::callback::SubKey;
use super::callback::server::Subscriptions;
use bifrost_hasher::hash_str;
use std::sync::Arc;
use parking_lot::{RwLock};
use std::collections::{HashMap, HashSet};
use utils::bincode;

pub const CONFIG_SM_ID: u64 = 1;

pub struct RaftMember {
    pub rpc: Arc<SyncServiceClient>,
    pub address: String,
    pub id: u64,
}

pub struct Configures {
    pub members: HashMap<u64, RaftMember>,
    pub subscriptions: Arc<RwLock<Subscriptions>>,
    service_id: u64,
}

pub type MemberConfigSnapshot = HashSet<String>;

#[derive(Serialize, Deserialize, Debug)]
pub struct ConfigSnapshot {
    members: MemberConfigSnapshot,
    //TODO: snapshot for subscriptions
}

raft_state_machine! {
    def cmd new_member_(address: String);
    def cmd del_member_(address: String);
    def qry member_address() -> Vec<String>;

    def cmd subscribe(key: SubKey, address: String, session_id: u64) -> u64;
}

impl StateMachineCmds for Configures {
    fn new_member_(&mut self, address: String) -> Result<(), ()> {
        let addr = address.clone();
        let id = hash_str(&addr);
        if !self.members.contains_key(&id) {
            match rpc::DEFAULT_CLIENT_POOL.get(&address) {
                Ok(client) => {
                    self.members.insert(id, RaftMember {
                        rpc: SyncServiceClient::new(self.service_id, &client),
                        address: address,
                        id: id,
                    });
                    return Ok(());
                },
                Err(_) => {}
            }
        }
        Err(())
    }
    fn del_member_(&mut self, address: String) -> Result<(),()> {
        let hash = hash_str(&address);
        self.members.remove(&hash);
        Ok(())
    }
    fn member_address(&self) -> Result<Vec<String>,()> {
        let mut members = Vec::with_capacity(self.members.len());
        for (_, member) in self.members.iter() {
            members.push(member.address.clone());
        }
        Ok(members)
    }
    fn subscribe(&mut self, key: SubKey, address: String, session_id: u64) -> Result<u64, ()> {
        let mut subs = self.subscriptions.write();
        subs.subscribe(key, &address, session_id)
    }
}

impl StateMachineCtl for Configures {
    raft_sm_complete!();
    fn snapshot(&self) -> Option<Vec<u8>> {
        let mut snapshot = ConfigSnapshot{
            members: HashSet::with_capacity(self.members.len()),
        };
        for (_, member) in self.members.iter() {
            snapshot.members.insert(member.address.clone());
        }
        Some(bincode::serialize(&snapshot))
    }
    fn recover(&mut self, data: Vec<u8>) {
        let snapshot:ConfigSnapshot = bincode::deserialize(&data);
        self.recover_members(&snapshot.members)
    }
    fn id(&self) -> u64 {CONFIG_SM_ID}
}

impl Configures {
    pub fn new(service_id: u64) -> Configures {
        Configures {
            members: HashMap::new(),
            service_id: service_id,
            subscriptions: Arc::new(RwLock::new(Subscriptions::new()))
        }
    }
    fn recover_members (&mut self, snapshot: &MemberConfigSnapshot) {
        let mut curr_members: MemberConfigSnapshot = HashSet::with_capacity(self.members.len());
        for (_, member) in self.members.iter() {
            curr_members.insert(member.address.clone());
        }
        let to_del = curr_members.difference(snapshot);
        let to_add = snapshot.difference(&curr_members);
        for addr in to_del {
            self.del_member(addr.clone());
        }
        for addr in to_add {
            self.new_member(addr.clone());
        }
    }
    pub fn new_member(&mut self, address: String) -> Result<(),()> {
        self.new_member_(address)
    }
    pub fn del_member(&mut self, address: String) -> Result<(),()> {
        self.del_member_(address)
    }
    pub fn member_existed(&self, id: u64) -> bool {
        self.members.contains_key(&id)
    }
}<commit_msg>supress some warning<commit_after>use raft::SyncServiceClient;
use rpc;
use super::*;
use super::callback::SubKey;
use super::callback::server::Subscriptions;
use bifrost_hasher::hash_str;
use std::sync::Arc;
use parking_lot::{RwLock};
use std::collections::{HashMap, HashSet};
use utils::bincode;

pub const CONFIG_SM_ID: u64 = 1;

pub struct RaftMember {
    pub rpc: Arc<SyncServiceClient>,
    pub address: String,
    pub id: u64,
}

pub struct Configures {
    pub members: HashMap<u64, RaftMember>,
    // keep it in arc lock for reference in callback server.rs
    pub subscriptions: Arc<RwLock<Subscriptions>>,
    service_id: u64,
}

pub type MemberConfigSnapshot = HashSet<String>;

#[derive(Serialize, Deserialize, Debug)]
pub struct ConfigSnapshot {
    members: MemberConfigSnapshot,
    //TODO: snapshot for subscriptions
}

raft_state_machine! {
    def cmd new_member_(address: String);
    def cmd del_member_(address: String);
    def qry member_address() -> Vec<String>;

    def cmd subscribe(key: SubKey, address: String, session_id: u64) -> u64;
}

impl StateMachineCmds for Configures {
    fn new_member_(&mut self, address: String) -> Result<(), ()> {
        let addr = address.clone();
        let id = hash_str(&addr);
        if !self.members.contains_key(&id) {
            match rpc::DEFAULT_CLIENT_POOL.get(&address) {
                Ok(client) => {
                    self.members.insert(id, RaftMember {
                        rpc: SyncServiceClient::new(self.service_id, &client),
                        address,
                        id,
                    });
                    return Ok(());
                },
                Err(_) => {}
            }
        }
        Err(())
    }
    fn del_member_(&mut self, address: String) -> Result<(),()> {
        let hash = hash_str(&address);
        self.members.remove(&hash);
        Ok(())
    }
    fn member_address(&self) -> Result<Vec<String>,()> {
        let mut members = Vec::with_capacity(self.members.len());
        for (_, member) in self.members.iter() {
            members.push(member.address.clone());
        }
        Ok(members)
    }
    fn subscribe(&mut self, key: SubKey, address: String, session_id: u64) -> Result<u64, ()> {
        let mut subs = self.subscriptions.write();
        subs.subscribe(key, &address, session_id)
    }
}

impl StateMachineCtl for Configures {
    raft_sm_complete!();
    fn snapshot(&self) -> Option<Vec<u8>> {
        let mut snapshot = ConfigSnapshot{
            members: HashSet::with_capacity(self.members.len()),
        };
        for (_, member) in self.members.iter() {
            snapshot.members.insert(member.address.clone());
        }
        Some(bincode::serialize(&snapshot))
    }
    fn recover(&mut self, data: Vec<u8>) {
        let snapshot:ConfigSnapshot = bincode::deserialize(&data);
        self.recover_members(&snapshot.members)
    }
    fn id(&self) -> u64 {CONFIG_SM_ID}
}

impl Configures {
    pub fn new(service_id: u64) -> Configures {
        Configures {
            members: HashMap::new(),
            service_id: service_id,
            subscriptions: Arc::new(RwLock::new(Subscriptions::new()))
        }
    }
    fn recover_members (&mut self, snapshot: &MemberConfigSnapshot) {
        let mut curr_members: MemberConfigSnapshot = HashSet::with_capacity(self.members.len());
        for (_, member) in self.members.iter() {
            curr_members.insert(member.address.clone());
        }
        let to_del = curr_members.difference(snapshot);
        let to_add = snapshot.difference(&curr_members);
        for addr in to_del {
            self.del_member(addr.clone());
        }
        for addr in to_add {
            self.new_member(addr.clone());
        }
    }
    pub fn new_member(&mut self, address: String) -> Result<(),()> {
        self.new_member_(address)
    }
    pub fn del_member(&mut self, address: String) -> Result<(),()> {
        self.del_member_(address)
    }
    pub fn member_existed(&self, id: u64) -> bool {
        self.members.contains_key(&id)
    }
}<|endoftext|>


<commit_before>#![feature(auto_traits)]

// @has auto_aliases/trait.Bar.html '//h3[@aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
pub struct Foo;

pub auto trait Bar {}
<commit_msg>rustdoc: update auto_aliases test case with data-aliases attribute<commit_after>#![feature(auto_traits)]

// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
pub struct Foo;

pub auto trait Bar {}
<|endoftext|>


<commit_before>// Portion that builds and runs tests.  Assumes that this can be
// done via a call to `make build` and `make test`.  Compiler failure
// is assumed to be communicated by return value.  Tests are assumed
// to have the following output format:
//
// some test name: <PASS|FAIL>
//
// ...where each test result is on its own line.  If multiple tests
// have the same name, then only the last test is recorded.

use std::collections::HashMap;
use std::io::{BufferedReader, AsRefReader, RefReader, IoResult,
              IoError, OtherIoError};
use std::io::pipe::PipeStream;
use std::io::process::{Command, Process, ExitStatus, ExitSignal,
                       ProcessExit};

fn spawn_with_timeout(c: &Command, timeout: Option<u64>) -> IoResult<Process> {
    let mut p = try!(c.spawn());
    p.set_timeout(timeout);
    Ok(p)
}

/// Runs the given command with the given timeout, ignoring the output.
/// If it returns non-zero, then it's a failure, as with a signal.
/// Takes what it should return on success.
pub fn run_command<A>(c: &Command, timeout: Option<u64>, on_success: A) -> IoResult<A> {
    (try!(
        (try!(
            spawn_with_timeout(c, timeout)))
            .wait())).if_ok(on_success)
}

trait ErrorSimplifier {
    fn if_ok<A>(&self, ret_this: A) -> IoResult<A>;
}

impl ErrorSimplifier for ProcessExit {
    fn if_ok<A>(&self, ret_this: A) -> IoResult<A> {
        match *self {
            ExitStatus(0) => Ok(ret_this),
            ExitStatus(x) => Err(
                IoError {
                    kind: OtherIoError,
                    desc: "Non-zero exit code",
                    detail: Some(x.to_string())
                }),
            ExitSignal(x) => Err(
                IoError {
                    kind: OtherIoError,
                    desc: "Exit signal",
                    detail: Some(x.to_string())
                })
        }
    }
}

#[deriving(Show, PartialEq)]
pub enum TestResult {
    Pass,
    Fail
}

struct ProcessReader {
    p: Process
}

impl ProcessReader {
    fn new(cmd: &Command, timeout: Option<u64>) -> IoResult<ProcessReader> {
        spawn_with_timeout(cmd, timeout).map(|p| ProcessReader { p: p })
    }

    fn output_reader<'a>(&'a mut self) -> BufferedReader<RefReader<'a, PipeStream>> {
        // unwrap should be ok - the documentation says `Some` is the default,
        // and we are not messing with any of the defaults
        BufferedReader::new(
            self.p.stdout.as_mut().unwrap().by_ref())
    }
}

fn parse_test_result(line: &str) -> IoResult<TestResult> {
    match line {
        "PASS" => Ok(Pass),
        "FAIL" => Ok(Fail),
        _ => Err(
            IoError {
                kind: OtherIoError,
                desc: "Malformed test result",
                detail: Some(line.to_string())
            })
    }
}

fn parse_line(line: &str) -> IoResult<(String, TestResult)> {
    let results: Vec<&str> = line.split_str(":").collect();
    if results.len() == 2 {
        parse_test_result(results[1]).map(|res| {
            (results[0].to_string(), res)
        })
    } else {
        Err(
            IoError {
                kind: OtherIoError,
                desc: "Malformed test string",
                detail: Some(line.to_string())
            })
    }
}

#[deriving(Show)]
pub enum BuildResult {
    SetupEnvFailure(IoError),
    BuildFailure(IoError),
    TestFailure(IoError),
    TestSuccess(HashMap<String, TestResult>)
}

pub trait WholeBuildable {
    // BEGIN FUNCTIONS TO IMPLEMENT
    fn env_timeout(&self) -> Option<u64>;
    fn env_command(&self) -> Command;

    fn build_timeout(&self) -> Option<u64>;
    fn build_command(&self) -> Command;

    fn test_timeout(&self) -> Option<u64>;
    fn test_command(&self) -> Command;
    // END FUNCTIONS TO IMPLEMENT

    /// Gets everything in order for testing to be performed.
    /// After calling this, it is assumed that we are ready
    /// to call make
    fn setup_env(&self) -> IoResult<()> {
        run_command(&self.env_command(), self.env_timeout(), ())
    }

    fn do_build(&self) -> IoResult<()> {
        run_command(&self.build_command(), self.build_timeout(), ())
    }

    fn do_testing(&self) -> IoResult<HashMap<String, TestResult>> {
        let mut reader =
            try!(ProcessReader::new(&self.test_command(), self.test_timeout()));
        let mut map = HashMap::new();
        for op_line in reader.output_reader().lines() {
            let (k, v) = try!(
                parse_line(
                    try!(op_line).as_slice().trim()));
            map.insert(k, v);
        }

        Ok(map)
    }

    fn whole_build(&self) -> BuildResult {
        // Because we have different results for different kinds
        // of failures, we cannot use `try!`
        match self.setup_env() {
            Ok(_) => {
                match self.do_build() {
                    Ok(_) => {
                        match self.do_testing() {
                            Ok(res) => TestSuccess(res),
                            Err(e) => TestFailure(e)
                        }
                    },
                    Err(e) => BuildFailure(e)
                }
            },
            Err(e) => SetupEnvFailure(e)
        }
    }
}

pub trait ToWholeBuildable<A : WholeBuildable> {
    fn to_whole_buildable(&self) -> A;
}

#[cfg(test)]
mod process_tests {
    use std::io::process::Command;
    use super::{run_command, ProcessReader};

    #[test]
    fn echo_ok() {
        assert!(run_command(&*Command::new("echo").arg("foobar"), None, ()).is_ok());
    }

    #[test]
    fn false_ok() {
        assert!(run_command(&Command::new("false"), None, ()).is_err());
    }

    fn output_from_command(cmd: &Command) -> Vec<String> {
        let pr = ProcessReader::new(cmd, None);
        assert!(pr.is_ok());
        pr.unwrap().output_reader().lines()
            .map(|line| {
                assert!(line.is_ok());
                line.unwrap().as_slice().trim().to_string()
            }).collect()
    }

    #[test]
    fn output_single_line_read() {
        let lines = output_from_command(
            &*Command::new("sh").arg("-c").arg("echo foobar"));
        assert_eq!(lines.len(), 1);
        assert_eq!(lines[0].as_slice(), "foobar");
    }

    #[test]
    fn output_multi_line_read() {
        let lines = output_from_command(
            &*Command::new("sh").arg("-c").arg("echo foo; echo bar"));
        assert_eq!(lines.len(), 2);
        assert_eq!(lines[0].as_slice(), "foo");
        assert_eq!(lines[1].as_slice(), "bar");
    }
}

#[cfg(test)]
mod parse_tests {
    use super::{parse_test_result, Pass, Fail, parse_line};

    #[test]
    fn parse_test_pass() {
        let res = parse_test_result("PASS");
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), Pass);
    }

    #[test]
    fn parse_test_fail() {
        let res = parse_test_result("FAIL");
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), Fail);
    }

    #[test]
    fn parse_test_bad_test() {
        let res = parse_test_result("foobar");
        assert!(res.is_err());
    }

    #[test]
    fn parse_valid_test_line() {
        let res = parse_line("my test:PASS");
        assert!(res.is_ok());
        let (key, result) = res.unwrap();
        assert_eq!(key.as_slice(), "my test");
        assert_eq!(result, Pass);
    }

    #[test]
    fn parse_invalid_test_line() {
        assert!(parse_line("this:is:PASS").is_err());
    }
}

pub mod testing {
    use std::io::process::Command;

    use super::{run_command, WholeBuildable};

    pub struct TestingRequest {
        dir: Path, // directory where the build is to be performed
        makefile_loc: Path // where the makefile is located
    }

    impl TestingRequest {
        pub fn new(dir: Path, makefile_loc: Path) -> TestingRequest {
            TestingRequest {
                dir: dir,
                makefile_loc: makefile_loc
            }
        }

        fn make_with_arg<A : ToCStr>(&self, arg: A) -> Command {
            let mut c = Command::new("make");
            c.arg("-s").arg(arg).cwd(&self.dir);
            c
        }
    }

    impl Drop for TestingRequest {
        /// Automatically deletes the copied-over makefile on test end,
        /// along with any applicable executables (namely `a.out`)
        #[allow(unused_must_use)]
        fn drop(&mut self) {
            let dir = self.dir.as_str().unwrap();
            run_command(
                &*Command::new("rm")
                    .arg(format!("{}/makefile", dir))
                    .arg(format!("{}/a.out", dir)),
                None,
                ());
        }
    }

    impl WholeBuildable for TestingRequest {
        fn env_timeout(&self) -> Option<u64> { None }

        fn env_command(&self) -> Command {
            let mut c = Command::new("cp");
            c.arg(self.makefile_loc.as_str().unwrap());
            c.arg(self.dir.as_str().unwrap());
            c
        }

        fn build_timeout(&self) -> Option<u64> { None }

        fn build_command(&self) -> Command {
            self.make_with_arg("build")
        }

        fn test_timeout(&self) -> Option<u64> { None }

        fn test_command(&self) -> Command {
            self.make_with_arg("test")
        }
    }
}

#[cfg(test)]
mod build_tests {
    use super::{TestSuccess, Pass, Fail, WholeBuildable};
    use super::testing::TestingRequest;

    fn req(name: &str) -> TestingRequest {
        TestingRequest::new(
            Path::new(format!("test/{}", name).as_slice()),
            Path::new("test/makefile"))
    }

    #[test]
    fn makefile_copy_ok() {
        assert!(req("compile_error").setup_env().is_ok());
    }

    #[test]
    fn expected_compile_failure() {
        let r = req("compile_error");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_err());
    }

    #[test]
    fn expected_compile_success() {
        let r = req("compile_success");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_ok());
    }

    #[test]
    fn testing_parsing_empty_success() {
        let r = req("testing_parsing_empty_success");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_ok());
        let res = r.do_testing();
        assert!(res.is_ok());
        assert_eq!(res.unwrap().len(), 0);
    }

    #[test]
    fn testing_parsing_nonempty_success() {
        let r = req("testing_parsing_nonempty_success");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_ok());
        let res = r.do_testing();

        assert!(res.is_ok());
        let u = res.unwrap();
        assert_eq!(u.len(), 2);

        let t1 = u.find_equiv(&"test1".to_string());
        assert!(t1.is_some());
        assert_eq!(t1.unwrap(), &Pass);

        let t2 = u.find_equiv(&"test2".to_string());
        assert!(t2.is_some());
        assert_eq!(t2.unwrap(), &Fail);
    }

    #[test]
    fn test_whole_build() {
        match req("test_whole_build").whole_build() {
            TestSuccess(u) => {
                let t1 = u.find_equiv(&"test1".to_string());
                assert!(t1.is_some());
                assert_eq!(t1.unwrap(), &Pass);

                let t2 = u.find_equiv(&"test2".to_string());
                assert!(t2.is_some());
                assert_eq!(t2.unwrap(), &Fail);
            },
            _ => { assert!(false); }
        };
    }
}
<commit_msg>Have things compiling for the building end of github support; still need to test.<commit_after>// Portion that builds and runs tests.  Assumes that this can be
// done via a call to `make build` and `make test`.  Compiler failure
// is assumed to be communicated by return value.  Tests are assumed
// to have the following output format:
//
// some test name: <PASS|FAIL>
//
// ...where each test result is on its own line.  If multiple tests
// have the same name, then only the last test is recorded.

use std::collections::HashMap;
use std::io::{BufferedReader, AsRefReader, RefReader, IoResult,
              IoError, OtherIoError};
use std::io::pipe::PipeStream;
use std::io::process::{Command, Process, ExitStatus, ExitSignal,
                       ProcessExit};

fn spawn_with_timeout(c: &Command, timeout: Option<u64>) -> IoResult<Process> {
    let mut p = try!(c.spawn());
    p.set_timeout(timeout);
    Ok(p)
}

/// Runs the given command with the given timeout, ignoring the output.
/// If it returns non-zero, then it's a failure, as with a signal.
/// Takes what it should return on success.
pub fn run_command<A>(c: &Command, timeout: Option<u64>, on_success: A) -> IoResult<A> {
    (try!(
        (try!(
            spawn_with_timeout(c, timeout)))
            .wait())).if_ok(on_success)
}

// Runs the given chain of commands.  Returns the first error.
pub fn run_commands<A>(commands: &Vec<Command>, timeout: Option<u64>, on_success: A) -> IoResult<A> {
    for cmd in commands.iter() {
        try!(run_command(cmd, timeout.clone(), ()));
    }
    Ok(on_success)
}

trait ErrorSimplifier {
    fn if_ok<A>(&self, ret_this: A) -> IoResult<A>;
}

impl ErrorSimplifier for ProcessExit {
    fn if_ok<A>(&self, ret_this: A) -> IoResult<A> {
        match *self {
            ExitStatus(0) => Ok(ret_this),
            ExitStatus(x) => Err(
                IoError {
                    kind: OtherIoError,
                    desc: "Non-zero exit code",
                    detail: Some(x.to_string())
                }),
            ExitSignal(x) => Err(
                IoError {
                    kind: OtherIoError,
                    desc: "Exit signal",
                    detail: Some(x.to_string())
                })
        }
    }
}

#[deriving(Show, PartialEq)]
pub enum TestResult {
    Pass,
    Fail
}

struct ProcessReader {
    p: Process
}

impl ProcessReader {
    fn new(cmd: &Command, timeout: Option<u64>) -> IoResult<ProcessReader> {
        spawn_with_timeout(cmd, timeout).map(|p| ProcessReader { p: p })
    }

    fn output_reader<'a>(&'a mut self) -> BufferedReader<RefReader<'a, PipeStream>> {
        // unwrap should be ok - the documentation says `Some` is the default,
        // and we are not messing with any of the defaults
        BufferedReader::new(
            self.p.stdout.as_mut().unwrap().by_ref())
    }
}

fn parse_test_result(line: &str) -> IoResult<TestResult> {
    match line {
        "PASS" => Ok(Pass),
        "FAIL" => Ok(Fail),
        _ => Err(
            IoError {
                kind: OtherIoError,
                desc: "Malformed test result",
                detail: Some(line.to_string())
            })
    }
}

fn parse_line(line: &str) -> IoResult<(String, TestResult)> {
    let results: Vec<&str> = line.split_str(":").collect();
    if results.len() == 2 {
        parse_test_result(results[1]).map(|res| {
            (results[0].to_string(), res)
        })
    } else {
        Err(
            IoError {
                kind: OtherIoError,
                desc: "Malformed test string",
                detail: Some(line.to_string())
            })
    }
}

#[deriving(Show)]
pub enum BuildResult {
    SetupEnvFailure(IoError),
    BuildFailure(IoError),
    TestFailure(IoError),
    TestSuccess(HashMap<String, TestResult>)
}

pub trait WholeBuildable {
    // BEGIN FUNCTIONS TO IMPLEMENT
    fn env_timeout(&self) -> Option<u64>;
    fn env_commands(&self) -> Vec<Command>;

    fn build_timeout(&self) -> Option<u64>;
    fn build_commands(&self) -> Vec<Command>;

    fn test_timeout(&self) -> Option<u64>;
    fn test_command(&self) -> Command;
    // END FUNCTIONS TO IMPLEMENT

    /// Gets everything in order for testing to be performed.
    /// After calling this, it is assumed that we are ready
    /// to call make
    fn setup_env(&self) -> IoResult<()> {
        run_commands(&self.env_commands(), self.env_timeout(), ())
    }

    fn do_build(&self) -> IoResult<()> {
        run_commands(&self.build_commands(), self.build_timeout(), ())
    }

    fn do_testing(&self) -> IoResult<HashMap<String, TestResult>> {
        let mut reader =
            try!(ProcessReader::new(&self.test_command(), self.test_timeout()));
        let mut map = HashMap::new();
        for op_line in reader.output_reader().lines() {
            let (k, v) = try!(
                parse_line(
                    try!(op_line).as_slice().trim()));
            map.insert(k, v);
        }

        Ok(map)
    }

    fn whole_build(&self) -> BuildResult {
        // Because we have different results for different kinds
        // of failures, we cannot use `try!`
        match self.setup_env() {
            Ok(_) => {
                match self.do_build() {
                    Ok(_) => {
                        match self.do_testing() {
                            Ok(res) => TestSuccess(res),
                            Err(e) => TestFailure(e)
                        }
                    },
                    Err(e) => BuildFailure(e)
                }
            },
            Err(e) => SetupEnvFailure(e)
        }
    }
}

pub trait ToWholeBuildable<A : WholeBuildable> {
    fn to_whole_buildable(&self) -> A;
}

pub mod github {
    extern crate url;
    extern crate github;

    use std::io::Command;
    use std::slice::Splits;
    use std::path::posix::StrComponents;

    use self::github::notification::PushNotification;
    use self::url::Url;

    use super::WholeBuildable;
    use super::testing::TestingRequest;

    pub struct GitHubRequest {
        build_root: Path,
        branch: String,
        clone_url: Url,
        testing_req: TestingRequest,
    }

    impl GitHubRequest {
        pub fn new<'a>(pn: &'a PushNotification, build_root: Path, makefile_loc: Path) -> GitHubRequest {
            let mut dir = build_root.clone();

            // Compiler could not infer quite a bit here, hence the explicit
            // lets and annotations.
            let fp: Path = pn.clone_url.to_file_path().unwrap();
            let mut components: StrComponents = fp.str_components();
            let trim: &[_] = &['.', 'g', 'i', 't'];
            dir.push(components.last().unwrap().unwrap()
                     .trim_right_chars(trim));

            GitHubRequest {
                build_root: build_root,
                branch: pn.branch.clone(),
                clone_url: pn.clone_url.clone(),
                testing_req: TestingRequest::new(dir, makefile_loc)
            }
        }
    }

    impl WholeBuildable for GitHubRequest {
        fn env_timeout(&self) -> Option<u64> { None }
        fn build_timeout(&self) -> Option<u64> { None }
        fn test_timeout(&self) -> Option<u64> { None }

        fn env_commands(&self) -> Vec<Command> {
            let mut parent = self.testing_req.env_commands();
            let mut clone = Command::new("git");
            clone.arg("clone").arg("-b").arg(self.branch.as_slice());
            clone.arg(self.clone_url.serialize());
            clone.cwd(&self.build_root);

            parent.push(clone);
            parent
        }

        fn build_commands(&self) -> Vec<Command> {
            self.testing_req.build_commands()
        }

        fn test_command(&self) -> Command {
            self.testing_req.test_command()
        }
    }
}

#[cfg(test)]
mod process_tests {
    use std::io::process::Command;
    use super::{run_command, ProcessReader};

    #[test]
    fn echo_ok() {
        assert!(run_command(&*Command::new("echo").arg("foobar"), None, ()).is_ok());
    }

    #[test]
    fn false_ok() {
        assert!(run_command(&Command::new("false"), None, ()).is_err());
    }

    fn output_from_command(cmd: &Command) -> Vec<String> {
        let pr = ProcessReader::new(cmd, None);
        assert!(pr.is_ok());
        pr.unwrap().output_reader().lines()
            .map(|line| {
                assert!(line.is_ok());
                line.unwrap().as_slice().trim().to_string()
            }).collect()
    }

    #[test]
    fn output_single_line_read() {
        let lines = output_from_command(
            &*Command::new("sh").arg("-c").arg("echo foobar"));
        assert_eq!(lines.len(), 1);
        assert_eq!(lines[0].as_slice(), "foobar");
    }

    #[test]
    fn output_multi_line_read() {
        let lines = output_from_command(
            &*Command::new("sh").arg("-c").arg("echo foo; echo bar"));
        assert_eq!(lines.len(), 2);
        assert_eq!(lines[0].as_slice(), "foo");
        assert_eq!(lines[1].as_slice(), "bar");
    }
}

#[cfg(test)]
mod parse_tests {
    use super::{parse_test_result, Pass, Fail, parse_line};

    #[test]
    fn parse_test_pass() {
        let res = parse_test_result("PASS");
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), Pass);
    }

    #[test]
    fn parse_test_fail() {
        let res = parse_test_result("FAIL");
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), Fail);
    }

    #[test]
    fn parse_test_bad_test() {
        let res = parse_test_result("foobar");
        assert!(res.is_err());
    }

    #[test]
    fn parse_valid_test_line() {
        let res = parse_line("my test:PASS");
        assert!(res.is_ok());
        let (key, result) = res.unwrap();
        assert_eq!(key.as_slice(), "my test");
        assert_eq!(result, Pass);
    }

    #[test]
    fn parse_invalid_test_line() {
        assert!(parse_line("this:is:PASS").is_err());
    }
}

pub mod testing {
    use std::io::process::Command;

    use super::{run_command, WholeBuildable};

    pub struct TestingRequest {
        dir: Path, // directory where the build is to be performed
        makefile_loc: Path // where the makefile is located
    }

    impl TestingRequest {
        pub fn new(dir: Path, makefile_loc: Path) -> TestingRequest {
            TestingRequest {
                dir: dir,
                makefile_loc: makefile_loc
            }
        }

        fn make_with_arg<A : ToCStr>(&self, arg: A) -> Command {
            let mut c = Command::new("make");
            c.arg("-s").arg(arg).cwd(&self.dir);
            c
        }
    }

    impl Drop for TestingRequest {
        /// Automatically deletes the copied-over makefile on test end,
        /// along with any applicable executables (namely `a.out`)
        #[allow(unused_must_use)]
        fn drop(&mut self) {
            let dir = self.dir.as_str().unwrap();
            run_command(
                &*Command::new("rm")
                    .arg(format!("{}/makefile", dir))
                    .arg(format!("{}/a.out", dir)),
                None,
                ());
        }
    }

    impl WholeBuildable for TestingRequest {
        fn env_timeout(&self) -> Option<u64> { None }

        fn env_commands(&self) -> Vec<Command> {
            let mut c = Command::new("cp");
            c.arg(self.makefile_loc.as_str().unwrap());
            c.arg(self.dir.as_str().unwrap());
            vec!(c)
        }

        fn build_timeout(&self) -> Option<u64> { None }

        fn build_commands(&self) -> Vec<Command> {
            vec!(self.make_with_arg("build"))
        }

        fn test_timeout(&self) -> Option<u64> { None }

        fn test_command(&self) -> Command {
            self.make_with_arg("test")
        }
    }
}

#[cfg(test)]
mod build_tests {
    use super::{TestSuccess, Pass, Fail, WholeBuildable};
    use super::testing::TestingRequest;

    fn req(name: &str) -> TestingRequest {
        TestingRequest::new(
            Path::new(format!("test/{}", name).as_slice()),
            Path::new("test/makefile"))
    }

    #[test]
    fn makefile_copy_ok() {
        assert!(req("compile_error").setup_env().is_ok());
    }

    #[test]
    fn expected_compile_failure() {
        let r = req("compile_error");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_err());
    }

    #[test]
    fn expected_compile_success() {
        let r = req("compile_success");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_ok());
    }

    #[test]
    fn testing_parsing_empty_success() {
        let r = req("testing_parsing_empty_success");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_ok());
        let res = r.do_testing();
        assert!(res.is_ok());
        assert_eq!(res.unwrap().len(), 0);
    }

    #[test]
    fn testing_parsing_nonempty_success() {
        let r = req("testing_parsing_nonempty_success");
        assert!(r.setup_env().is_ok());
        assert!(r.do_build().is_ok());
        let res = r.do_testing();

        assert!(res.is_ok());
        let u = res.unwrap();
        assert_eq!(u.len(), 2);

        let t1 = u.find_equiv(&"test1".to_string());
        assert!(t1.is_some());
        assert_eq!(t1.unwrap(), &Pass);

        let t2 = u.find_equiv(&"test2".to_string());
        assert!(t2.is_some());
        assert_eq!(t2.unwrap(), &Fail);
    }

    #[test]
    fn test_whole_build() {
        match req("test_whole_build").whole_build() {
            TestSuccess(u) => {
                let t1 = u.find_equiv(&"test1".to_string());
                assert!(t1.is_some());
                assert_eq!(t1.unwrap(), &Pass);

                let t2 = u.find_equiv(&"test2".to_string());
                assert!(t2.is_some());
                assert_eq!(t2.unwrap(), &Fail);
            },
            _ => { assert!(false); }
        };
    }
}
<|endoftext|>