<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

//! A library providing the written english form of a number.
//!
//! # Example
//!
//! ```rust
//! use numeral::Cardinal;
//!
//! let n = 127;
//! println!("{} is written: {}", n, n.cardinal());
//! ```

#![warn(missing_docs)]

const NUMBER: [&'static str; 20] = [
    "zero",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "ten",
    "eleven",
    "twelve",
    "thirteen",
    "fourteen",
    "fifteen",
    "sixteen",
    "seventeen",
    "eighteen",
    "nineteen",
];

const TENS: [&'static str; 10] = [
    "",
    "",
    "twenty",
    "thirty",
    "forty",
    "fifty",
    "sixty",
    "seventy",
    "eighty",
    "ninety",
];

const MULTIPLIER: [&'static str; 9] = [
    "",
    "thousand",
    "million",
    "billion",
    "trillion",
    "quadrillion",
    "quintillion",
    "sextillion",
    "septillion",
];

/// Provides the cardinal written form of a number.
pub trait Cardinal {
    /// Yields the cardinal form of a number.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use numeral::Cardinal;
    /// let written_form = 127.cardinal();
    /// assert_eq!(written_form, "one hundred twenty-seven");
    /// ```
    fn cardinal(&self) -> String;
}

macro_rules! impl_numeral_signed {
    ($($numtype:ty),*) => ($(
        impl Cardinal for $numtype {
            fn cardinal(&self) -> String {
                cardinal_int(i64::from(*self).abs() as u64, self.is_negative())
            }
        }
    )*)
}

impl_numeral_signed!(i8, i16, i32);

macro_rules! impl_numeral_unsigned {
    ($($numtype:ty),*) => ($(
        impl Cardinal for $numtype {
            fn cardinal(&self) -> String {
                cardinal_int(u64::from(*self), false)
            }
        }
    )*)
}

impl_numeral_unsigned!(u8, u16, u32, u64);

impl Cardinal for i64 {
    fn cardinal(&self) -> String {
        let n_abs = if *self == i64::min_value() { *self as u64 } else { self.abs() as u64 };
        cardinal_int(n_abs, self.is_negative())
    }
}

impl Cardinal for isize {
    fn cardinal(&self) -> String {
        let n_abs = if *self == isize::min_value() { *self as usize } else { self.abs() as usize };
        cardinal_int(n_abs as u64, self.is_negative())
    }
}

impl Cardinal for usize {
    fn cardinal(&self) -> String {
        cardinal_int(*self as u64, false)
    }
}

/// Returns the written form of any 64-bit integer
/// as a vector of strings.
fn cardinal_int(n: u64, negative: bool) -> String {
    if n == 0 { return String::from(NUMBER[0]) }
    let multiple_order = ((n as f32).log10() as u32) / 3;
    let max_len = multiple_order as usize * 8 + 6;
    let mut cardinal = Vec::with_capacity(max_len);
    if negative { cardinal.push("minus "); }
    compose_cardinal_int(n, multiple_order, &mut cardinal);
    debug_assert!(cardinal.len() <= max_len);
    cardinal.concat()
}

macro_rules! push {
    ($vec:ident, $table:ident[$index:ident]) => (
        debug_assert!(($index as usize) < $table.len(), format!("{} out of {}'s range", stringify!($index), stringify!($table)));
        $vec.push($table[$index as usize]);
    )
}

/// Pushes the strings composing the cardinal form of any unsigned 64-bit number
/// on a vector. Zero is ignored.
fn compose_cardinal_int(mut n: u64, mut multiple_order: u32, cardinal: &mut Vec<&str>) {
    debug_assert!(n != 0, "n == 0 in compose_cardinal_int()");
    debug_assert!(multiple_order == ((n as f32).log10() as u32) / 3, "wrong value for multiple_order in compose_cardinal_int()");

    if multiple_order > 0 {
        let mut multiplier = 10u64.pow(multiple_order * 3);
        let mut multiplicand;
        loop {
            multiplicand = n / multiplier;
            n %= multiplier;
            if multiplicand != 0 {
                push_triplet(multiplicand, cardinal);
                cardinal.push(" ");
                push!(cardinal, MULTIPLIER[multiple_order]);
                if n != 0 { cardinal.push(" "); }
                else { return }
            }
            multiple_order -= 1;
            if multiple_order == 0 { break }
            multiplier /= 1000;
        }
    }
    push_triplet(n, cardinal);
}

/// Takes an integer in [1,999] and adds it's written form
/// to a cardinal in construction. Zero is ignored.
fn push_triplet(n: u64, cardinal: &mut Vec<&str>) {
    debug_assert!(n != 0, "n == 0 in push_triplet()");
    debug_assert!(n < 1000, "n >= 1000 in push_triplet()");

    let hundreds = n / 100;
    let rest = n % 100;
    if hundreds != 0 {
        push!(cardinal, NUMBER[hundreds]);
        if rest == 0 { cardinal.push(" hundred"); return }
        else { cardinal.push(" hundred "); }
    }
    push_doublet(rest, cardinal);
}

/// Takes an integer in [1,99] and adds it's written form
/// to a cardinal in construction. Zero is ignored.
fn push_doublet(n: u64, cardinal: &mut Vec<&str>) {
    debug_assert!(n != 0, "n == 0 in push_doublet()");
    debug_assert!(n < 100, "n >= 100 in push_doublet()");

    if n < 20  {
        push!(cardinal, NUMBER[n]);
    }
    else {
        let tens = n / 10;
        let ones = n % 10;
        push!(cardinal, TENS[tens]);
        if ones != 0 {
            cardinal.push("-");
            push!(cardinal, NUMBER[ones]);
        }
    }
}
<commit_msg>clippy: should assert eq/ne<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

//! A library providing the written english form of a number.
//!
//! # Example
//!
//! ```rust
//! use numeral::Cardinal;
//!
//! let n = 127;
//! println!("{} is written: {}", n, n.cardinal());
//! ```

#![warn(missing_docs)]

const NUMBER: [&'static str; 20] = [
    "zero",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "ten",
    "eleven",
    "twelve",
    "thirteen",
    "fourteen",
    "fifteen",
    "sixteen",
    "seventeen",
    "eighteen",
    "nineteen",
];

const TENS: [&'static str; 10] = [
    "",
    "",
    "twenty",
    "thirty",
    "forty",
    "fifty",
    "sixty",
    "seventy",
    "eighty",
    "ninety",
];

const MULTIPLIER: [&'static str; 9] = [
    "",
    "thousand",
    "million",
    "billion",
    "trillion",
    "quadrillion",
    "quintillion",
    "sextillion",
    "septillion",
];

/// Provides the cardinal written form of a number.
pub trait Cardinal {
    /// Yields the cardinal form of a number.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use numeral::Cardinal;
    /// let written_form = 127.cardinal();
    /// assert_eq!(written_form, "one hundred twenty-seven");
    /// ```
    fn cardinal(&self) -> String;
}

macro_rules! impl_numeral_signed {
    ($($numtype:ty),*) => ($(
        impl Cardinal for $numtype {
            fn cardinal(&self) -> String {
                cardinal_int(i64::from(*self).abs() as u64, self.is_negative())
            }
        }
    )*)
}

impl_numeral_signed!(i8, i16, i32);

macro_rules! impl_numeral_unsigned {
    ($($numtype:ty),*) => ($(
        impl Cardinal for $numtype {
            fn cardinal(&self) -> String {
                cardinal_int(u64::from(*self), false)
            }
        }
    )*)
}

impl_numeral_unsigned!(u8, u16, u32, u64);

impl Cardinal for i64 {
    fn cardinal(&self) -> String {
        let n_abs = if *self == i64::min_value() { *self as u64 } else { self.abs() as u64 };
        cardinal_int(n_abs, self.is_negative())
    }
}

impl Cardinal for isize {
    fn cardinal(&self) -> String {
        let n_abs = if *self == isize::min_value() { *self as usize } else { self.abs() as usize };
        cardinal_int(n_abs as u64, self.is_negative())
    }
}

impl Cardinal for usize {
    fn cardinal(&self) -> String {
        cardinal_int(*self as u64, false)
    }
}

/// Returns the written form of any 64-bit integer
/// as a vector of strings.
fn cardinal_int(n: u64, negative: bool) -> String {
    if n == 0 { return String::from(NUMBER[0]) }
    let multiple_order = ((n as f32).log10() as u32) / 3;
    let max_len = multiple_order as usize * 8 + 6;
    let mut cardinal = Vec::with_capacity(max_len);
    if negative { cardinal.push("minus "); }
    compose_cardinal_int(n, multiple_order, &mut cardinal);
    debug_assert!(cardinal.len() <= max_len);
    cardinal.concat()
}

macro_rules! push {
    ($vec:ident, $table:ident[$index:ident]) => (
        debug_assert!(($index as usize) < $table.len(), format!("{} out of {}'s range", stringify!($index), stringify!($table)));
        $vec.push($table[$index as usize]);
    )
}

/// Pushes the strings composing the cardinal form of any unsigned 64-bit number
/// on a vector. Zero is ignored.
fn compose_cardinal_int(mut n: u64, mut multiple_order: u32, cardinal: &mut Vec<&str>) {
    debug_assert_ne!(n, 0, "n == 0 in compose_cardinal_int()");
    debug_assert_eq!(multiple_order, ((n as f32).log10() as u32) / 3, "wrong value for multiple_order in compose_cardinal_int()");

    if multiple_order > 0 {
        let mut multiplier = 10u64.pow(multiple_order * 3);
        let mut multiplicand;
        loop {
            multiplicand = n / multiplier;
            n %= multiplier;
            if multiplicand != 0 {
                push_triplet(multiplicand, cardinal);
                cardinal.push(" ");
                push!(cardinal, MULTIPLIER[multiple_order]);
                if n != 0 { cardinal.push(" "); }
                else { return }
            }
            multiple_order -= 1;
            if multiple_order == 0 { break }
            multiplier /= 1000;
        }
    }
    push_triplet(n, cardinal);
}

/// Takes an integer in [1,999] and adds it's written form
/// to a cardinal in construction. Zero is ignored.
fn push_triplet(n: u64, cardinal: &mut Vec<&str>) {
    debug_assert_ne!(n, 0, "n == 0 in push_triplet()");
    debug_assert!(n < 1000, "n >= 1000 in push_triplet()");

    let hundreds = n / 100;
    let rest = n % 100;
    if hundreds != 0 {
        push!(cardinal, NUMBER[hundreds]);
        if rest == 0 { cardinal.push(" hundred"); return }
        else { cardinal.push(" hundred "); }
    }
    push_doublet(rest, cardinal);
}

/// Takes an integer in [1,99] and adds it's written form
/// to a cardinal in construction. Zero is ignored.
fn push_doublet(n: u64, cardinal: &mut Vec<&str>) {
    debug_assert_ne!(n, 0, "n == 0 in push_doublet()");
    debug_assert!(n < 100, "n >= 100 in push_doublet()");

    if n < 20  {
        push!(cardinal, NUMBER[n]);
    }
    else {
        let tens = n / 10;
        let ones = n % 10;
        push!(cardinal, TENS[tens]);
        if ones != 0 {
            cardinal.push("-");
            push!(cardinal, NUMBER[ones]);
        }
    }
}
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: uint = 4096;
pub const DISPLAY_WIDTH: uint = 64;
pub const DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8; 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8; MEM_SIZE],
    v: [u8; 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16; 16],
    display: [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool; 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0; MEM_SIZE],
            v: [0; 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0; 16],
            display: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false; 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET.as_slice());
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<commit_msg>Update to latest rustc<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: uint = 4096;
pub const DISPLAY_WIDTH: uint = 64;
pub const DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8; 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8; MEM_SIZE],
    v: [u8; 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16; 16],
    display: [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool; 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0; MEM_SIZE],
            v: [0; 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0; 16],
            display: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false; 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET.as_slice());
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        (b1 as u16) << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]
#![feature(stmt_expr_attributes)]

extern crate rand;
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
#[cfg(all(unix, test))] extern crate nix;

mod alloc;

pub use alloc::{ unprotected_mprotect, malloc, allocarray, free };

// -- memcmp --

/// Constant time memcmp.
pub unsafe fn memcmp<T>(b1: *const T, b2: *const T, len: usize) -> i32 {
    let b1 = b1 as *const u8;
    let b2 = b2 as *const u8;
    let mut d = 0;
    for i in 0..len as isize {
        d |= *b1.offset(i) ^ *b2.offset(i);
    }
    (1 & (d as i32 - 1) >> 8) - 1
}

// -- memset / memzero --

/// General memset.
#[cfg(not(HAVE_MEMSET_S))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    let s = s as *mut u8;
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
}

/// Call memset_s.
#[cfg(HAVE_MEMSET_S)]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    extern {
        fn memset_s(s: *mut libc::c_void, smax: libc::size_t, c: libc::c_int, n: libc::size_t) -> libc::c_int;
    }
    memset_s(s as libc::c_void, n, c, n);
}

/// General memzero.
#[cfg(all(unix, not(HAVE_EXPLICIT_BZERO)))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    memset(dest, 0, n);
}

/// Call explicit_bzero.
#[cfg(all(unix, HAVE_EXPLICIT_BZERO))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    extern {
        fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
    }
    explicit_bzero(dest as *mut libc::c_void, n);
}

/// call SecureZeroMemory.
#[cfg(windows)]
pub unsafe fn memzero<T>(s: *mut T, n: usize) {
    extern "system" {
        fn SecureZeroMemory(ptr: winapi::PVOID, cnt: winapi::SIZE_T);
    }
    SecureZeroMemory(s as winapi::PVOID, n as winapi::SIZE_T);
}

// -- mlock / munlock --

#[cfg(target_os = "linux")]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DONTDUMP);
}

#[cfg(target_os = "linux")]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DODUMP);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_NOCORE);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_CORE);
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dontdump<T>(_addr: *mut T, _len: usize) { }

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dodump<T>(_addr: *mut T, _len: usize) { }

/// Unix mlock.
#[cfg(unix)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    dontdump(addr, len);
    libc::mlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualLock.
#[cfg(windows)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    kernel32::VirtualLock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

/// Unix munlock.
#[cfg(unix)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    dodump(addr, len);
    libc::munlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualUnlock.
#[cfg(windows)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    kernel32::VirtualUnlock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

// -- mprotect --

/// Prot enum.
#[derive(Debug, Clone, PartialEq)]
pub enum Prot {
    #[cfg(unix)] NoAccess = libc::PROT_NONE as isize,
    #[cfg(unix)] ReadOnly = libc::PROT_READ as isize,
    #[cfg(unix)] WriteOnly = libc::PROT_WRITE as isize,
    #[cfg(unix)] ReadWrite = (libc::PROT_READ | libc::PROT_WRITE) as isize,
    #[cfg(unix)] Execute = libc::PROT_EXEC as isize,
    #[cfg(unix)] ReadExec = (libc::PROT_READ | libc::PROT_EXEC) as isize,
    #[cfg(unix)] WriteExec = (libc::PROT_WRITE | libc::PROT_EXEC) as isize,
    #[cfg(unix)] ReadWriteExec = (libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as isize,

    #[cfg(windows)] NoAccess = winapi::PAGE_NOACCESS as isize,
    #[cfg(windows)] ReadOnly = winapi::PAGE_READONLY as isize,
    #[cfg(windows)] ReadWrite = winapi::PAGE_READWRITE as isize,
    #[cfg(windows)] WriteCopy = winapi::PAGE_WRITECOPY as isize,
    #[cfg(windows)] Execute = winapi::PAGE_EXECUTE as isize,
    #[cfg(windows)] ReadExec = winapi::PAGE_EXECUTE_READ as isize,
    #[cfg(windows)] ReadWriteExec = winapi::PAGE_EXECUTE_READWRITE as isize,
    #[cfg(windows)] WriteCopyExec = winapi::PAGE_EXECUTE_WRITECOPY as isize,
    #[cfg(windows)] Guard = winapi::PAGE_GUARD as isize,
    #[cfg(windows)] NoCache = winapi::PAGE_NOCACHE as isize,
    #[cfg(windows)] WriteCombine = winapi::PAGE_WRITECOMBINE as isize,
    #[cfg(windows)] RevertToFileMap = winapi::PAGE_REVERT_TO_FILE_MAP as isize,
    #[cfg(windows)] TargetsNoUpdate = winapi::PAGE_TARGETS_NO_UPDATE as isize,
    #[cfg(windows)] TargetsInvalid = winapi::PAGE_TARGETS_INVALID as isize,
}

/// Unix mprotect.
#[cfg(unix)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    libc::mprotect(ptr as *mut libc::c_void, len, prot as libc::c_int) == 0
}

/// Windows VirtualProtect.
#[cfg(windows)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    kernel32::VirtualProtect(
        ptr as winapi::LPVOID,
        len as winapi::SIZE_T,
        prot as winapi::DWORD,
        std::ptr::null_mut()
    ) != 0
}
<commit_msg>fix cfg(windows) + Prot remove TargetsInvalid<commit_after>#![feature(core_intrinsics)]
#![feature(stmt_expr_attributes)]

extern crate rand;
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
#[cfg(all(unix, test))] extern crate nix;

mod alloc;

pub use alloc::{ unprotected_mprotect, malloc, allocarray, free };

// -- memcmp --

/// Constant time memcmp.
pub unsafe fn memcmp<T>(b1: *const T, b2: *const T, len: usize) -> i32 {
    let b1 = b1 as *const u8;
    let b2 = b2 as *const u8;
    let mut d = 0;
    for i in 0..len as isize {
        d |= *b1.offset(i) ^ *b2.offset(i);
    }
    (1 & (d as i32 - 1) >> 8) - 1
}

// -- memset / memzero --

/// General memset.
#[cfg(not(HAVE_MEMSET_S))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    let s = s as *mut u8;
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
}

/// Call memset_s.
#[cfg(HAVE_MEMSET_S)]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    extern {
        fn memset_s(s: *mut libc::c_void, smax: libc::size_t, c: libc::c_int, n: libc::size_t) -> libc::c_int;
    }
    memset_s(s as libc::c_void, n, c, n);
}

/// General memzero.
#[cfg(all(unix, not(HAVE_EXPLICIT_BZERO)))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    memset(dest, 0, n);
}

/// Call explicit_bzero.
#[cfg(all(unix, HAVE_EXPLICIT_BZERO))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    extern {
        fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
    }
    explicit_bzero(dest as *mut libc::c_void, n);
}

/// call SecureZeroMemory.
#[cfg(windows)]
pub unsafe fn memzero<T>(s: *mut T, n: usize) {
    extern "system" {
        fn SecureZeroMemory(ptr: winapi::PVOID, cnt: winapi::SIZE_T);
    }
    SecureZeroMemory(s as winapi::PVOID, n as winapi::SIZE_T);
}

// -- mlock / munlock --

#[cfg(target_os = "linux")]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DONTDUMP);
}

#[cfg(target_os = "linux")]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DODUMP);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_NOCORE);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_CORE);
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dontdump<T>(_addr: *mut T, _len: usize) { }

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dodump<T>(_addr: *mut T, _len: usize) { }

/// Unix mlock.
#[cfg(unix)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    dontdump(addr, len);
    libc::mlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualLock.
#[cfg(windows)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    kernel32::VirtualLock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

/// Unix munlock.
#[cfg(unix)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    dodump(addr, len);
    libc::munlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualUnlock.
#[cfg(windows)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    kernel32::VirtualUnlock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

// -- mprotect --

/// Prot enum.
#[derive(Debug, Clone, PartialEq)]
pub enum Prot {
    #[cfg(unix)] NoAccess = libc::PROT_NONE as isize,
    #[cfg(unix)] ReadOnly = libc::PROT_READ as isize,
    #[cfg(unix)] WriteOnly = libc::PROT_WRITE as isize,
    #[cfg(unix)] ReadWrite = (libc::PROT_READ | libc::PROT_WRITE) as isize,
    #[cfg(unix)] Execute = libc::PROT_EXEC as isize,
    #[cfg(unix)] ReadExec = (libc::PROT_READ | libc::PROT_EXEC) as isize,
    #[cfg(unix)] WriteExec = (libc::PROT_WRITE | libc::PROT_EXEC) as isize,
    #[cfg(unix)] ReadWriteExec = (libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as isize,

    #[cfg(windows)] NoAccess = winapi::PAGE_NOACCESS as isize,
    #[cfg(windows)] ReadOnly = winapi::PAGE_READONLY as isize,
    #[cfg(windows)] ReadWrite = winapi::PAGE_READWRITE as isize,
    #[cfg(windows)] WriteCopy = winapi::PAGE_WRITECOPY as isize,
    #[cfg(windows)] Execute = winapi::PAGE_EXECUTE as isize,
    #[cfg(windows)] ReadExec = winapi::PAGE_EXECUTE_READ as isize,
    #[cfg(windows)] ReadWriteExec = winapi::PAGE_EXECUTE_READWRITE as isize,
    #[cfg(windows)] WriteCopyExec = winapi::PAGE_EXECUTE_WRITECOPY as isize,
    #[cfg(windows)] Guard = winapi::PAGE_GUARD as isize,
    #[cfg(windows)] NoCache = winapi::PAGE_NOCACHE as isize,
    #[cfg(windows)] WriteCombine = winapi::PAGE_WRITECOMBINE as isize,
    #[cfg(windows)] RevertToFileMap = winapi::PAGE_REVERT_TO_FILE_MAP as isize,
    #[cfg(windows)] TargetsNoUpdate = winapi::PAGE_TARGETS_NO_UPDATE as isize,

    // winapi::PAGE_REVERT_TO_FILE_MAP == winapi::PAGE_TARGETS_NO_UPDATE
    // #[cfg(windows)] TargetsInvalid = winapi::PAGE_TARGETS_INVALID as isize,
}

/// Unix mprotect.
#[cfg(unix)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    libc::mprotect(ptr as *mut libc::c_void, len, prot as libc::c_int) == 0
}

/// Windows VirtualProtect.
#[cfg(windows)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    kernel32::VirtualProtect(
        ptr as winapi::LPVOID,
        len as winapi::SIZE_T,
        prot as winapi::DWORD,
        std::ptr::null_mut()
    ) != 0
}
<|endoftext|>


<commit_before>//! A library providing a generic connection pool.
#![feature(unsafe_destructor, phase)]
#![warn(missing_doc)]
#![doc(html_root_url="http://www.rust-ci.org/sfackler/r2d2/doc")]

#[phase(plugin, link)]
extern crate log;
extern crate serialize;

use std::comm;
use std::collections::{Deque, RingBuf};
use std::sync::{Arc, Mutex};
use std::fmt;

pub use config::Config;

mod config;

/// A trait which provides database-specific functionality.
pub trait PoolManager<C, E>: Send+Sync {
    /// Attempts to create a new connection.
    fn connect(&self) -> Result<C, E>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut C) -> Result<(), E>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut C) -> bool;
}

/// A trait which handles errors reported by the `PoolManager`.
pub trait ErrorHandler<E>: Send+Sync {
    /// Handles a connection error.
    fn handle_error(&self, error: E);
}

impl<E> ErrorHandler<E> for Box<ErrorHandler<E>+Sync+Send> {
    fn handle_error(&self, error: E) {
        (**self).handle_error(error)
    }
}

/// An `ErrorHandler` which does nothing.
pub struct NoopErrorHandler;

impl<E> ErrorHandler<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// An `ErrorHandler` which logs at the error level.
pub struct LoggingErrorHandler;

impl<E> ErrorHandler<E> for LoggingErrorHandler where E: fmt::Show {
    fn handle_error(&self, error: E) {
        error!("Error opening connection: {}", error);
    }
}

/// An error type returned if pool creation fails.
#[deriving(PartialEq, Eq)]
pub enum NewPoolError<E> {
    /// The provided pool configuration was invalid.
    InvalidConfig(&'static str),
    /// The manager returned an error when creating a connection.
    ConnectionError(E),
}

impl<E> fmt::Show for NewPoolError<E> where E: fmt::Show {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidConfig(ref error) => write!(f, "Invalid config: {}", error),
            ConnectionError(ref error) => write!(f, "Unable to create connections: {}", error),
        }
    }
}

enum Command<C> {
    AddConnection,
    TestConnection(C),
}

struct PoolInternals<C> {
    conns: RingBuf<C>,
    num_conns: uint,
}

struct InnerPool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    config: Config,
    manager: M,
    error_handler: H,
    internals: Mutex<PoolInternals<C>>,
}

/// A generic connection pool.
pub struct Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    helper_chan: Mutex<Sender<Command<C>>>,
    inner: Arc<InnerPool<C, E, M, H>>
}

impl<C, E, M, H> Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    /// Creates a new connection pool.
    pub fn new(config: Config, manager: M, error_handler: H)
               -> Result<Pool<C, E, M, H>, NewPoolError<E>> {
        try!(config.validate().map_err(InvalidConfig));

        let mut internals = PoolInternals {
            conns: RingBuf::new(),
            num_conns: config.pool_size,
        };

        for _ in range(0, config.pool_size) {
            match manager.connect() {
                Ok(conn) => internals.conns.push(conn),
                Err(err) => return Err(ConnectionError(err)),
            }
        }

        let inner = Arc::new(InnerPool {
            config: config,
            manager: manager,
            error_handler: error_handler,
            internals: Mutex::new(internals),
        });

        let (sender, receiver) = comm::channel();
        // FIXME :(
        let receiver = Arc::new(Mutex::new(receiver));

        for _ in range(0, config.helper_tasks) {
            let inner = inner.clone();
            let receiver = receiver.clone();
            spawn(proc() helper_task(receiver, inner));
        }

        Ok(Pool {
            helper_chan: Mutex::new(sender),
            inner: inner,
        })
    }

    /// Retrieves a connection from the pool.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, C, E, M, H>, ()> {
        let mut internals = self.inner.internals.lock();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.inner.config.test_on_check_out {
                        match self.inner.manager.is_valid(&mut conn) {
                            Ok(()) => {}
                            Err(e) => {
                                self.inner.error_handler.handle_error(e);
                                internals = self.inner.internals.lock();
                                internals.num_conns -= 1;
                                continue;
                            }
                        }
                    }

                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn),
                    })
                }
                None => internals.cond.wait(),
            }
        }
    }

    fn put_back(&self, mut conn: C) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.inner.manager.has_broken(&mut conn);

        let mut internals = self.inner.internals.lock();
        if broken {
            internals.num_conns -= 1;
        } else {
            internals.conns.push(conn);
            internals.cond.signal();
        }
    }
}

fn helper_task<C, E, M, H>(receiver: Arc<Mutex<Receiver<Command<C>>>>,
                           inner: Arc<InnerPool<C, E, M, H>>)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    loop {
        let mut receiver = receiver.lock();
        let res = receiver.recv_opt();
        drop(receiver);

        match res {
            Ok(AddConnection) => add_connection(&*inner),
            Ok(TestConnection(conn)) => test_connection(&*inner, conn),
            Err(()) => break,
        }
    }
}

fn add_connection<C, E, M, H>(inner: &InnerPool<C, E, M, H>)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    match inner.manager.connect() {
        Ok(conn) => {
            let mut internals = inner.internals.lock();
            internals.conns.push(conn);
            internals.num_conns += 1;
            internals.cond.signal();
        }
        Err(err) => inner.error_handler.handle_error(err),
    }
}

fn test_connection<C, E, M, H>(inner: &InnerPool<C, E, M, H>, mut conn: C)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    let is_valid = inner.manager.is_valid(&mut conn);
    let mut internals = inner.internals.lock();
    match is_valid {
        Ok(()) => internals.conns.push(conn),
        Err(e) => {
            inner.error_handler.handle_error(e);
            internals.num_conns -= 1;
        }
    }
}

/// A smart pointer wrapping an underlying connection.
pub struct PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    pool: &'a Pool<C, E, M, H>,
    conn: Option<C>,
}

#[unsafe_destructor]
impl<'a, C, E, M, H> Drop for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<'a, C, E, M, H> Deref<C> for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn deref(&self) -> &C {
        self.conn.as_ref().unwrap()
    }
}
<commit_msg>Clarify docs<commit_after>//! A library providing a generic connection pool.
#![feature(unsafe_destructor, phase)]
#![warn(missing_doc)]
#![doc(html_root_url="http://www.rust-ci.org/sfackler/r2d2/doc")]

#[phase(plugin, link)]
extern crate log;
extern crate serialize;

use std::comm;
use std::collections::{Deque, RingBuf};
use std::sync::{Arc, Mutex};
use std::fmt;

pub use config::Config;

mod config;

/// A trait which provides database-specific functionality.
pub trait PoolManager<C, E>: Send+Sync {
    /// Attempts to create a new connection.
    fn connect(&self) -> Result<C, E>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut C) -> Result<(), E>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut C) -> bool;
}

/// A trait which handles errors reported by the `PoolManager`.
pub trait ErrorHandler<E>: Send+Sync {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

impl<E> ErrorHandler<E> for Box<ErrorHandler<E>+Sync+Send> {
    fn handle_error(&self, error: E) {
        (**self).handle_error(error)
    }
}

/// An `ErrorHandler` which does nothing.
pub struct NoopErrorHandler;

impl<E> ErrorHandler<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// An `ErrorHandler` which logs at the error level.
pub struct LoggingErrorHandler;

impl<E> ErrorHandler<E> for LoggingErrorHandler where E: fmt::Show {
    fn handle_error(&self, error: E) {
        error!("Error opening connection: {}", error);
    }
}

/// An error type returned if pool creation fails.
#[deriving(PartialEq, Eq)]
pub enum NewPoolError<E> {
    /// The provided pool configuration was invalid.
    InvalidConfig(&'static str),
    /// The manager returned an error when creating a connection.
    ConnectionError(E),
}

impl<E> fmt::Show for NewPoolError<E> where E: fmt::Show {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidConfig(ref error) => write!(f, "Invalid config: {}", error),
            ConnectionError(ref error) => write!(f, "Unable to create connections: {}", error),
        }
    }
}

enum Command<C> {
    AddConnection,
    TestConnection(C),
}

struct PoolInternals<C> {
    conns: RingBuf<C>,
    num_conns: uint,
}

struct InnerPool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    config: Config,
    manager: M,
    error_handler: H,
    internals: Mutex<PoolInternals<C>>,
}

/// A generic connection pool.
pub struct Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    helper_chan: Mutex<Sender<Command<C>>>,
    inner: Arc<InnerPool<C, E, M, H>>
}

impl<C, E, M, H> Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    /// Creates a new connection pool.
    pub fn new(config: Config, manager: M, error_handler: H)
               -> Result<Pool<C, E, M, H>, NewPoolError<E>> {
        try!(config.validate().map_err(InvalidConfig));

        let mut internals = PoolInternals {
            conns: RingBuf::new(),
            num_conns: config.pool_size,
        };

        for _ in range(0, config.pool_size) {
            match manager.connect() {
                Ok(conn) => internals.conns.push(conn),
                Err(err) => return Err(ConnectionError(err)),
            }
        }

        let inner = Arc::new(InnerPool {
            config: config,
            manager: manager,
            error_handler: error_handler,
            internals: Mutex::new(internals),
        });

        let (sender, receiver) = comm::channel();
        // FIXME :(
        let receiver = Arc::new(Mutex::new(receiver));

        for _ in range(0, config.helper_tasks) {
            let inner = inner.clone();
            let receiver = receiver.clone();
            spawn(proc() helper_task(receiver, inner));
        }

        Ok(Pool {
            helper_chan: Mutex::new(sender),
            inner: inner,
        })
    }

    /// Retrieves a connection from the pool.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, C, E, M, H>, ()> {
        let mut internals = self.inner.internals.lock();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.inner.config.test_on_check_out {
                        match self.inner.manager.is_valid(&mut conn) {
                            Ok(()) => {}
                            Err(e) => {
                                self.inner.error_handler.handle_error(e);
                                internals = self.inner.internals.lock();
                                internals.num_conns -= 1;
                                continue;
                            }
                        }
                    }

                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn),
                    })
                }
                None => internals.cond.wait(),
            }
        }
    }

    fn put_back(&self, mut conn: C) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.inner.manager.has_broken(&mut conn);

        let mut internals = self.inner.internals.lock();
        if broken {
            internals.num_conns -= 1;
        } else {
            internals.conns.push(conn);
            internals.cond.signal();
        }
    }
}

fn helper_task<C, E, M, H>(receiver: Arc<Mutex<Receiver<Command<C>>>>,
                           inner: Arc<InnerPool<C, E, M, H>>)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    loop {
        let mut receiver = receiver.lock();
        let res = receiver.recv_opt();
        drop(receiver);

        match res {
            Ok(AddConnection) => add_connection(&*inner),
            Ok(TestConnection(conn)) => test_connection(&*inner, conn),
            Err(()) => break,
        }
    }
}

fn add_connection<C, E, M, H>(inner: &InnerPool<C, E, M, H>)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    match inner.manager.connect() {
        Ok(conn) => {
            let mut internals = inner.internals.lock();
            internals.conns.push(conn);
            internals.num_conns += 1;
            internals.cond.signal();
        }
        Err(err) => inner.error_handler.handle_error(err),
    }
}

fn test_connection<C, E, M, H>(inner: &InnerPool<C, E, M, H>, mut conn: C)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    let is_valid = inner.manager.is_valid(&mut conn);
    let mut internals = inner.internals.lock();
    match is_valid {
        Ok(()) => internals.conns.push(conn),
        Err(e) => {
            inner.error_handler.handle_error(e);
            internals.num_conns -= 1;
        }
    }
}

/// A smart pointer wrapping an underlying connection.
pub struct PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    pool: &'a Pool<C, E, M, H>,
    conn: Option<C>,
}

#[unsafe_destructor]
impl<'a, C, E, M, H> Drop for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<'a, C, E, M, H> Deref<C> for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn deref(&self) -> &C {
        self.conn.as_ref().unwrap()
    }
}
<|endoftext|>


<commit_before>#![crate_name = "irc"]
#![crate_type = "dylib"]
#![feature(convert, hasher_write, slice_patterns)]

#![allow(stable_features)]
// hasher_write was stabilised in rust 1.4

#![deny(unused_must_use, unused_variables, unused_mut)]

#[macro_use] extern crate log;

pub use self::event::IrcEvent;

pub use self::watchers::{
    RegisterError,
    RegisterErrorType,

    JoinResult,
    JoinSuccess,
    JoinError,

    WhoResult,
    WhoRecord,
    WhoSuccess,
    WhoError,

    BundlerManager,
    JoinBundlerTrigger,
    WhoBundlerTrigger,
};

pub use self::irccase::{
    IrcAsciiExt,
    OwnedIrcAsciiExt,
};

pub use self::state::{
    User,
    UserId,

    Channel,
    ChannelId,

    State,
    FrozenState,
    MessageEndpoint,
};

#[cfg(test)] pub mod testinfra;
mod numerics;
mod watchers;
mod core_plugins;

/// Experimental message types
pub mod message_types;

/// Experimental utility code
pub mod util;

/// Experimental parsing code
pub mod parse;

pub mod identifier;

pub mod stream;

/// Event types
mod event;

/// IRC case manipulation
mod irccase;

/// IRC state tracker
mod state;

/// Receive buffer
pub mod recv;
<commit_msg>Remove crate information from lib.rs<commit_after>#![feature(convert, hasher_write, slice_patterns)]

#![allow(stable_features)]
// hasher_write was stabilised in rust 1.4

#![deny(unused_must_use, unused_variables, unused_mut)]

#[macro_use] extern crate log;

pub use self::event::IrcEvent;

pub use self::watchers::{
    RegisterError,
    RegisterErrorType,

    JoinResult,
    JoinSuccess,
    JoinError,

    WhoResult,
    WhoRecord,
    WhoSuccess,
    WhoError,

    BundlerManager,
    JoinBundlerTrigger,
    WhoBundlerTrigger,
};

pub use self::irccase::{
    IrcAsciiExt,
    OwnedIrcAsciiExt,
};

pub use self::state::{
    User,
    UserId,

    Channel,
    ChannelId,

    State,
    FrozenState,
    MessageEndpoint,
};

#[cfg(test)] pub mod testinfra;
mod numerics;
mod watchers;
mod core_plugins;

/// Experimental message types
pub mod message_types;

/// Experimental utility code
pub mod util;

/// Experimental parsing code
pub mod parse;

pub mod identifier;

pub mod stream;

/// Event types
mod event;

/// IRC case manipulation
mod irccase;

/// IRC state tracker
mod state;

/// Receive buffer
pub mod recv;
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::slice;

#[derive(Debug, Copy, Clone)]
pub struct _0;
#[derive(Debug, Copy, Clone)]
pub struct _1;

/// Single type-level bit, `_0` or `_1`.
pub trait Bit { }
impl Bit for _0 { }
impl Bit for _1 { }

/// Nonnegative type-level integer, e.g., `((_1,_0),_1) = 0b101 = 25`.
pub trait Nat {
    fn reify() -> u64;
}
impl Nat for _0 { fn reify() -> u64 { 0 } }
impl Nat for _1 { fn reify() -> u64 { 1 } }
impl<N: Nat> Nat for (N, _0) {
    fn reify() -> u64 { N::reify() << 1 }
}
impl<N: Nat> Nat for (N, _1) {
    fn reify() -> u64 { (N::reify() << 1) | 1 }
}

/// Trait making GenericArray work
pub unsafe trait ArrayLength<T> : Nat {
	/// Associated type representing the array type for the number
	type ArrayType;
}

/// Empty array - needed to end recursion
#[allow(dead_code)]
pub struct EmptyArray<T> {
	_marker: PhantomData<T>
}

/// Array with a single element - for _1
#[allow(dead_code)]
#[repr(C)]
pub struct UnitArray<T> {
	data: T
}

unsafe impl<T> ArrayLength<T> for _0 {
	type ArrayType = EmptyArray<T>;
}
unsafe impl<T> ArrayLength<T> for _1 {
	type ArrayType = UnitArray<T>;
}

#[allow(dead_code)]
#[repr(C)]
pub struct GenericArrayImplEven<T, U> {
	parent1: U,
	parent2: U,
	_marker: PhantomData<T>
}

#[allow(dead_code)]
#[repr(C)]
pub struct GenericArrayImplOdd<T, U> {
	parent1: U,
	parent2: U,
	data: T
}

unsafe impl<T, N: ArrayLength<T>> ArrayLength<T> for (N, _0) {
	type ArrayType = GenericArrayImplEven<T, N::ArrayType>;
}

unsafe impl<T, N: ArrayLength<T>> ArrayLength<T> for (N, _1) {
	type ArrayType = GenericArrayImplOdd<T, N::ArrayType>;
}

#[allow(dead_code)]
pub struct GenericArray<T, U: ArrayLength<T>> {
	data: U::ArrayType
}

impl<T, N> Deref for GenericArray<T, N> where N: ArrayLength<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe {
            slice::from_raw_parts(self as *const Self as *const T, N::reify() as usize)
        }
    }
}

impl<T, N> DerefMut for GenericArray<T, N> where N: ArrayLength<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(self as *mut Self as *mut T, N::reify() as usize)
        }
    }
}

impl<T: Clone, N> GenericArray<T, N> where N: ArrayLength<T> {

	pub fn new() -> GenericArray<T, N> {
		unsafe { mem::zeroed() }
	}

	pub fn new_list(list: &[T]) -> GenericArray<T, N> {
		assert_eq!(list.len(), N::reify() as usize);
		let mut res = GenericArray::new();
		for i in 0..N::reify() as usize {
			res[i] = list[i].clone();
		}
		res
	}

}

#[cfg(test)]
mod test {
	use super::{_0, _1, GenericArray};

	type P97 = ((((((_1, _1), _0), _0), _0), _0), _1);

	#[test]
	fn test() {
		let mut list97 = [0; 97];
		for i in 0..97 {
			list97[i] = i as i32;
		}
	    let l : GenericArray<i32, P97> = GenericArray::new_list(&list97);
	    assert_eq!(l[0], 0);
	    assert_eq!(l[1], 1);
	    assert_eq!(l[32], 32);
	    assert_eq!(l[56], 56);
	}
}
<commit_msg>Simplify the base cases of the recursion, using () and T instead of custom structs.<commit_after>use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::slice;

#[derive(Debug, Copy, Clone)]
pub struct _0;
#[derive(Debug, Copy, Clone)]
pub struct _1;

/// Single type-level bit, `_0` or `_1`.
pub trait Bit { }
impl Bit for _0 { }
impl Bit for _1 { }

/// Nonnegative type-level integer, e.g., `((_1,_0),_1) = 0b101 = 25`.
pub trait Nat {
    fn reify() -> u64;
}
impl Nat for _0 { fn reify() -> u64 { 0 } }
impl Nat for _1 { fn reify() -> u64 { 1 } }
impl<N: Nat> Nat for (N, _0) {
    fn reify() -> u64 { N::reify() << 1 }
}
impl<N: Nat> Nat for (N, _1) {
    fn reify() -> u64 { (N::reify() << 1) | 1 }
}

/// Trait making GenericArray work
pub unsafe trait ArrayLength<T> : Nat {
	/// Associated type representing the array type for the number
	type ArrayType;
}

unsafe impl<T> ArrayLength<T> for _0 {
	type ArrayType = ();
}
unsafe impl<T> ArrayLength<T> for _1 {
	type ArrayType = T;
}

#[allow(dead_code)]
#[repr(C)]
pub struct GenericArrayImplEven<T, U> {
	parent1: U,
	parent2: U,
	_marker: PhantomData<T>
}

#[allow(dead_code)]
#[repr(C)]
pub struct GenericArrayImplOdd<T, U> {
	parent1: U,
	parent2: U,
	data: T
}

unsafe impl<T, N: ArrayLength<T>> ArrayLength<T> for (N, _0) {
	type ArrayType = GenericArrayImplEven<T, N::ArrayType>;
}

unsafe impl<T, N: ArrayLength<T>> ArrayLength<T> for (N, _1) {
	type ArrayType = GenericArrayImplOdd<T, N::ArrayType>;
}

#[allow(dead_code)]
pub struct GenericArray<T, U: ArrayLength<T>> {
	data: U::ArrayType
}

impl<T, N> Deref for GenericArray<T, N> where N: ArrayLength<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe {
            slice::from_raw_parts(self as *const Self as *const T, N::reify() as usize)
        }
    }
}

impl<T, N> DerefMut for GenericArray<T, N> where N: ArrayLength<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe {
            slice::from_raw_parts_mut(self as *mut Self as *mut T, N::reify() as usize)
        }
    }
}

impl<T: Clone, N> GenericArray<T, N> where N: ArrayLength<T> {

	pub fn new() -> GenericArray<T, N> {
		unsafe { mem::zeroed() }
	}

	pub fn new_list(list: &[T]) -> GenericArray<T, N> {
		assert_eq!(list.len(), N::reify() as usize);
		let mut res = GenericArray::new();
		for i in 0..N::reify() as usize {
			res[i] = list[i].clone();
		}
		res
	}

}

#[cfg(test)]
mod test {
	use super::{_0, _1, GenericArray};

	type P97 = ((((((_1, _1), _0), _0), _0), _0), _1);

	#[test]
	fn test() {
		let mut list97 = [0; 97];
		for i in 0..97 {
			list97[i] = i as i32;
		}
	    let l : GenericArray<i32, P97> = GenericArray::new_list(&list97);
	    assert_eq!(l[0], 0);
	    assert_eq!(l[1], 1);
	    assert_eq!(l[32], 32);
	    assert_eq!(l[56], 56);
	}
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;

use std::io;
use std::io::{Write, Read, Error, ErrorKind};
use nix::errno::Errno;
use nix::Error::Sys;
use nix::sys::termios;
use nix::sys::termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, ECHO, ICANON, IEXTEN, ISIG, VMIN, VTIME};

static MAX_LINE: i32 = 4096;
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb","cons25","emacs"];

fn is_a_tty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

fn is_unsupported_term() -> bool {
    let term = std::env::var("TERM").ok().unwrap();
    let mut unsupported = false;
    for iter in &UNSUPPORTED_TERM {
        unsupported = term == *iter
    }
    unsupported
}

fn enable_raw_mode() -> Result<termios::Termios, nix::Error> {
    if !is_a_tty() {
        Err(Sys(Errno::ENOTTY))
    } else {
        let original_term = try!(termios::tcgetattr(libc::STDIN_FILENO));
        let mut raw = original_term;
        raw.c_iflag = raw.c_iflag   & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        raw.c_oflag = raw.c_oflag   & !(OPOST);
        raw.c_cflag = raw.c_cflag   | (CS8);
        raw.c_lflag = raw.c_lflag   & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1;
        raw.c_cc[VTIME] = 0;
        try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &raw));
        Ok(original_term)
    }
}

fn disable_raw_mode(original_termios: termios::Termios) -> Result<(), nix::Error> {
    try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &original_termios));
    Ok(())
}

fn readline_raw() -> Result<String, io::Error> {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];

    if is_a_tty() {
        let original_termios = match enable_raw_mode() {
            Err(Sys(Errno::ENOTTY)) => return Err(Error::new(ErrorKind::Other, "Not a TTY")),
            Err(Sys(Errno::EBADF))  => Err(Error::new(ErrorKind::Other, "Not a file descriptor")),
            Err(..)                 => Err(Error::new(ErrorKind::Other, "Unknown Error")),
            Ok(term)                => term
        };

        let numread = io::stdin().read(&mut input).unwrap();
        buffer.push(input[0]);
        println!("Read #{:?} bytes with a value of{:?}",numread,input[0]);

        match disable_raw_mode(original_termios) {
            Err(..) => return Err(Error::new(ErrorKind::Other, "Failed to revert to original termios")),
            Ok(..)  => ()
        }
        Ok(String::from_utf8(buffer).unwrap())
    } else {

        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    }
}

pub fn readline(prompt: &'static str) -> Result<String, io::Error> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    try!(stdout.write(prompt.as_bytes()));
    try!(stdout.flush());

    if is_unsupported_term() {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    } else {
        readline_raw()
    }
}
<commit_msg>Fixed compile time errors... expecting a return<commit_after>extern crate libc;
extern crate nix;

use std::io;
use std::io::{Write, Read, Error, ErrorKind};
use nix::errno::Errno;
use nix::Error::Sys;
use nix::sys::termios;
use nix::sys::termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, ECHO, ICANON, IEXTEN, ISIG, VMIN, VTIME};

static MAX_LINE: i32 = 4096;
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb","cons25","emacs"];

fn is_a_tty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

fn is_unsupported_term() -> bool {
    let term = std::env::var("TERM").ok().unwrap();
    let mut unsupported = false;
    for iter in &UNSUPPORTED_TERM {
        unsupported = term == *iter
    }
    unsupported
}

fn enable_raw_mode() -> Result<termios::Termios, nix::Error> {
    if !is_a_tty() {
        Err(Sys(Errno::ENOTTY))
    } else {
        let original_term = try!(termios::tcgetattr(libc::STDIN_FILENO));
        let mut raw = original_term;
        raw.c_iflag = raw.c_iflag   & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        raw.c_oflag = raw.c_oflag   & !(OPOST);
        raw.c_cflag = raw.c_cflag   | (CS8);
        raw.c_lflag = raw.c_lflag   & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1;
        raw.c_cc[VTIME] = 0;
        try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &raw));
        Ok(original_term)
    }
}

fn disable_raw_mode(original_termios: termios::Termios) -> Result<(), nix::Error> {
    try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &original_termios));
    Ok(())
}

fn readline_raw() -> Result<String, io::Error> {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];

    if is_a_tty() {
        let original_termios = match enable_raw_mode() {
            Err(Sys(Errno::ENOTTY)) => return Err(Error::new(ErrorKind::Other, "Not a TTY")),
            Err(Sys(Errno::EBADF))  => return Err(Error::new(ErrorKind::Other, "Not a file descriptor")),
            Err(..)                 => return Err(Error::new(ErrorKind::Other, "Unknown Error")),
            Ok(term)                => term
        };

        let numread = io::stdin().read(&mut input).unwrap();
        buffer.push(input[0]);
        println!("Read #{:?} bytes with a value of{:?}",numread,input[0]);

        match disable_raw_mode(original_termios) {
            Err(..) => return Err(Error::new(ErrorKind::Other, "Failed to revert to original termios")),
            Ok(..)  => ()
        }
        Ok(String::from_utf8(buffer).unwrap())
    } else {

        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    }
}

pub fn readline(prompt: &'static str) -> Result<String, io::Error> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    try!(stdout.write(prompt.as_bytes()));
    try!(stdout.flush());

    if is_unsupported_term() {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    } else {
        readline_raw()
    }
}
<|endoftext|>


<commit_before>#![feature(convert)]

extern crate html5ever;
extern crate string_cache;

use std::convert::AsRef;
use std::path::Path;
use std::fs::{File, read_dir};
use std::io::{self, Read, Write};
use std::error::FromError;
use std::default::Default;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::mem::swap;

use html5ever::Attribute;
use html5ever::tokenizer::{Tokenizer, TokenSink, Tag, TagKind};
use html5ever::tokenizer::Token as HtmlToken;

use string_cache::atom::Atom;

pub use codegen::{JavaScript, JsVarState, Rust, RustVisibility};

use codegen::{Token, Content, Codegen, ContentType, Scope};
use fragments::{Fragment, ReturnType};

use parser::ExtensibleMap;

pub mod codegen;
pub mod fragments;
mod parser;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Parse(Vec<Cow<'static, str>>)
}

impl FromError<io::Error> for Error {
    fn from_error(e: io::Error) -> Error {
        Error::Io(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => e.fmt(f),
            &Error::Parse(ref e) => {
                try!(write!(f, "Parse errors: "));
                for (i, error) in e.iter().enumerate() {
                    if i == 0 {
                        try!(error.fmt(f));
                    } else {
                        try!(write!(f, ", {}", error));
                    }
                }
                Ok(())
            }
        }
    }
}

///A collection of templates.
pub struct TemplateGroup<'a> {
    templates: Vec<ParsedTemplate>,
    fragments: HashMap<&'static str, Box<Fragment + 'a>>
}

impl<'a> TemplateGroup<'a> {
    pub fn new() -> TemplateGroup<'a> {
        TemplateGroup {
            templates: vec![],
            fragments: init_fragments()
        }
    }

    ///Add a template from a string.
    pub fn parse_string(&mut self, name: String, source: String) -> Result<(), Error> {
        let mut template = Template::extending(&self.fragments);
        try!(template.parse_string(source));
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });

        Ok(())
    }

    ///Add every `*.html` and `*.htm` file in a directory to the template group.
    pub fn parse_directory<P: AsRef<Path>>(&mut self, dir: P) -> Result<(), Error> {
        let directory = try!(read_dir(dir));

        for path in directory {
            let path = try!(path).path();
            let info = (
                path.file_stem().and_then(|n| n.to_str()),
                path.extension().and_then(|e| e.to_str())
            );
            if let (Some(name), Some(ext)) = info {
                if ext == "html" || ext == "htm" {
                    let mut source = String::new();
                    try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut source)));
                    try!(self.parse_string(name.to_string(), source));
                }
            }
        }

        Ok(())
    }

    ///Add an already parsed template to the group.
    pub fn add_template(&mut self, name: String, template: Template) {
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, writer: &mut W, codegen: &C) -> io::Result<()> {
        codegen.build_module(writer, |w, indent| {
            for template in &self.templates {
                try!(codegen.build_template(w, &template.name, indent, &template.parameters, &template.tokens));
            }
            Ok(())
        })
    }
}

struct ParsedTemplate {
    name: String,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>
}

///A single template.
pub struct Template<'a> {
    fragments: ExtensibleMap<'a, &'static str, Box<Fragment + 'a>>,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>,
    errors: Vec<Cow<'static, str>>
}

impl<'a> Template<'a> {
    ///Create an empty template.
    pub fn new() -> Template<'a> {
        Template {
            fragments: ExtensibleMap::Owned(init_fragments()),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    fn extending(fragments: &'a HashMap<&'static str, Box<Fragment + 'a>>) -> Template<'a> {
        Template {
            fragments: ExtensibleMap::extend(fragments),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    ///Add content from a string to the template.
    pub fn parse_string(&mut self, source: String) -> Result<(), Error> {
        {
            let mut tokenizer = Tokenizer::new(&mut*self, Default::default());
            tokenizer.feed(source);
        }

        if self.errors.len() > 0 {
            let mut e = vec![];
            swap(&mut e, &mut self.errors);
            Err(Error::Parse(e))
        } else {
            Ok(())
        }
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, template_name: &str, writer: &mut W, codegen: &C) -> io::Result<()> {
        codegen.build_template(writer, template_name, 0, &self.parameters, &self.tokens)
    }

    fn open_tag(&mut self, name: Atom, attributes: Vec<Attribute>, self_closing: bool) -> Result<(), Cow<'static, str>> {
        let void = is_void(name.as_slice());
        self.tokens.push(Token::BeginTag(name));

        for attribute in attributes {
            let mut content = try!(parser::parse_content(&attribute.value, &self.fragments)).into_iter();
            match content.next() {
                Some(ReturnType::Content(Content::String(text))) => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(text))),
                Some(ReturnType::Content(Content::Placeholder(name))) => {
                    self.reg_string(name.clone());
                    self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::Placeholder(name)));
                },
                Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
                Some(ReturnType::Scope(scope)) => {
                    self.reg_scope_vars(&scope);
                    self.tokens.push(Token::Scope(scope));
                },
                Some(ReturnType::End) => self.tokens.push(Token::End),
                None => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(String::new())))
            }

            for part in content {
                match part {
                    ReturnType::Content(Content::String(text)) => self.tokens.push(Token::AppendToAttribute(Content::String(text))),
                    ReturnType::Content(Content::Placeholder(name)) => {
                        self.reg_string(name.clone());
                        self.tokens.push(Token::AppendToAttribute(Content::Placeholder(name)));
                    },
                    ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                    ReturnType::Scope(scope) => {
                        self.reg_scope_vars(&scope);
                        self.tokens.push(Token::Scope(scope));
                    },
                    ReturnType::End => self.tokens.push(Token::End),
                }
            }

            self.tokens.push(Token::EndAttribute);
        }

        self.tokens.push(Token::EndTag(void || self_closing));

        Ok(())
    }

    fn add_text(&mut self, text: String) -> Result<(), Cow<'static, str>> {
        let mut content = try!(parser::parse_content(&text, &self.fragments)).into_iter();
        match content.next() {
            Some(ReturnType::Content(Content::String(text))) => self.tokens.push(Token::BeginText(Content::String(text))),
            Some(ReturnType::Content(Content::Placeholder(name))) => {
                self.reg_string(name.clone());
                self.tokens.push(Token::BeginText(Content::Placeholder(name)));
            },
            Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
            Some(ReturnType::Scope(scope)) => {
                self.reg_scope_vars(&scope);
                self.tokens.push(Token::Scope(scope));
            },
            Some(ReturnType::End) => self.tokens.push(Token::End),
            None => return Ok(())
        }

        for part in content {
            match part {
                ReturnType::Content(Content::String(text)) => self.tokens.push(Token::AppendToText(Content::String(text))),
                ReturnType::Content(Content::Placeholder(name)) => {
                    self.reg_string(name.clone());
                    self.tokens.push(Token::AppendToText(Content::Placeholder(name)));
                },
                ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                ReturnType::Scope(scope) => {
                    self.reg_scope_vars(&scope);
                    self.tokens.push(Token::Scope(scope));
                },
                ReturnType::End => self.tokens.push(Token::End),
            }
        }
        self.tokens.push(Token::EndText);

        Ok(())
    }

    fn close_tag(&mut self, tag: Atom) {
        self.tokens.push(Token::CloseTag(tag));
    }

    fn reg_scope_vars(&mut self, scope: &Scope) {
        match scope {
            &Scope::If(ref logic) => logic.parameters(&mut |param| self.reg_bool(param.clone()))
        }
    }

    fn reg_string(&mut self, param: String) {
        match self.parameters.entry(param) {
            Entry::Occupied(mut entry) => match entry.get_mut() {
                &mut ContentType::String => {},
                entry => *entry = ContentType::OptionalString
            },
            Entry::Vacant(entry) => { entry.insert(ContentType::String); },
        }
    }

    fn reg_bool(&mut self, param: String) {
        match self.parameters.entry(param) {
            Entry::Occupied(mut entry) => match entry.get_mut() {
                &mut ContentType::Bool => {},
                entry => *entry = ContentType::OptionalString
            },
            Entry::Vacant(entry) => { entry.insert(ContentType::Bool); },
        }
    }
}

impl<'a, 'b: 'a> TokenSink for &'a mut Template<'b> {
    fn process_token(&mut self, token: HtmlToken) {
        match token {
            HtmlToken::TagToken(Tag {
                kind: TagKind::StartTag,
                name,
                attrs,
                self_closing
            }) => if let Err(e) = self.open_tag(name, attrs, self_closing) {
                self.errors.push(e);
            },
            HtmlToken::TagToken(Tag {
                kind: TagKind::EndTag,
                name,
                ..
            }) => self.close_tag(name),
            HtmlToken::CharacterTokens(text) => if let Err(e) = self.add_text(text) {
                self.errors.push(e);
            },
            _ => {}
        }
    }
}

// http://www.w3.org/TR/html5/syntax.html#void-elements
fn is_void(tag: &str) -> bool {
    match tag {
        "area" |
        "base" |
        "br" |
        "col" |
        "embed" |
        "hr" |
        "img" |
        "input" |
        "keygen" |
        "link" |
        "meta" |
        "param" |
        "source" |
        "track" |
        "wbr" => true,
        _ => false
    }
}

fn init_fragments<'a>() -> HashMap<&'static str, Box<Fragment + 'a>> {
    let mut map = HashMap::new();

    let f: Box<Fragment + 'a> = Box::new(fragments::If);
    map.insert(f.identifier(), f);

    let f = fragments::And;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Or;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Not;
    map.insert(f.identifier(), Box::new(f));

    map
}<commit_msg>Handle HTML errors<commit_after>#![feature(convert)]

extern crate html5ever;
extern crate string_cache;

use std::convert::AsRef;
use std::path::Path;
use std::fs::{File, read_dir};
use std::io::{self, Read, Write};
use std::error::FromError;
use std::default::Default;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::mem::swap;

use html5ever::Attribute;
use html5ever::tokenizer::{Tokenizer, TokenSink, Tag, TagKind};
use html5ever::tokenizer::Token as HtmlToken;

use string_cache::atom::Atom;

pub use codegen::{JavaScript, JsVarState, Rust, RustVisibility};

use codegen::{Token, Content, Codegen, ContentType, Scope};
use fragments::{Fragment, ReturnType};

use parser::ExtensibleMap;

pub mod codegen;
pub mod fragments;
mod parser;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Parse(Vec<Cow<'static, str>>)
}

impl FromError<io::Error> for Error {
    fn from_error(e: io::Error) -> Error {
        Error::Io(e)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => e.fmt(f),
            &Error::Parse(ref e) => {
                try!(write!(f, "Parse errors: "));
                for (i, error) in e.iter().enumerate() {
                    if i == 0 {
                        try!(error.fmt(f));
                    } else {
                        try!(write!(f, ", {}", error));
                    }
                }
                Ok(())
            }
        }
    }
}

///A collection of templates.
pub struct TemplateGroup<'a> {
    templates: Vec<ParsedTemplate>,
    fragments: HashMap<&'static str, Box<Fragment + 'a>>
}

impl<'a> TemplateGroup<'a> {
    pub fn new() -> TemplateGroup<'a> {
        TemplateGroup {
            templates: vec![],
            fragments: init_fragments()
        }
    }

    ///Add a template from a string.
    pub fn parse_string(&mut self, name: String, source: String) -> Result<(), Error> {
        let mut template = Template::extending(&self.fragments);
        try!(template.parse_string(source));
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });

        Ok(())
    }

    ///Add every `*.html` and `*.htm` file in a directory to the template group.
    pub fn parse_directory<P: AsRef<Path>>(&mut self, dir: P) -> Result<(), Error> {
        let directory = try!(read_dir(dir));

        for path in directory {
            let path = try!(path).path();
            let info = (
                path.file_stem().and_then(|n| n.to_str()),
                path.extension().and_then(|e| e.to_str())
            );
            if let (Some(name), Some(ext)) = info {
                if ext == "html" || ext == "htm" {
                    let mut source = String::new();
                    try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut source)));
                    try!(self.parse_string(name.to_string(), source));
                }
            }
        }

        Ok(())
    }

    ///Add an already parsed template to the group.
    pub fn add_template(&mut self, name: String, template: Template) {
        self.templates.push(ParsedTemplate {
            name: name,
            parameters: template.parameters,
            tokens: template.tokens
        });
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, writer: &mut W, codegen: &C) -> io::Result<()> {
        codegen.build_module(writer, |w, indent| {
            for template in &self.templates {
                try!(codegen.build_template(w, &template.name, indent, &template.parameters, &template.tokens));
            }
            Ok(())
        })
    }
}

struct ParsedTemplate {
    name: String,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>
}

///A single template.
pub struct Template<'a> {
    fragments: ExtensibleMap<'a, &'static str, Box<Fragment + 'a>>,
    parameters: HashMap<String, ContentType>,
    tokens: Vec<codegen::Token>,
    errors: Vec<Cow<'static, str>>
}

impl<'a> Template<'a> {
    ///Create an empty template.
    pub fn new() -> Template<'a> {
        Template {
            fragments: ExtensibleMap::Owned(init_fragments()),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    fn extending(fragments: &'a HashMap<&'static str, Box<Fragment + 'a>>) -> Template<'a> {
        Template {
            fragments: ExtensibleMap::extend(fragments),
            parameters: HashMap::new(),
            tokens: vec![],
            errors: vec![]
        }
    }

    ///Add content from a string to the template.
    pub fn parse_string(&mut self, source: String) -> Result<(), Error> {
        {
            let mut tokenizer = Tokenizer::new(&mut*self, Default::default());
            tokenizer.feed(source);
        }

        if self.errors.len() > 0 {
            let mut e = vec![];
            swap(&mut e, &mut self.errors);
            Err(Error::Parse(e))
        } else {
            Ok(())
        }
    }

    ///Register a custom fragment.
    pub fn register_fragment<F: Fragment + 'a>(&mut self, fragment: F) {
        let fragment = Box::new(fragment);
        self.fragments.insert(fragment.identifier(), fragment);
    }

    ///Write template code.
    pub fn emit_code<W: Write, C: Codegen>(&self, template_name: &str, writer: &mut W, codegen: &C) -> io::Result<()> {
        codegen.build_template(writer, template_name, 0, &self.parameters, &self.tokens)
    }

    fn open_tag(&mut self, name: Atom, attributes: Vec<Attribute>, self_closing: bool) -> Result<(), Cow<'static, str>> {
        let void = is_void(name.as_slice());
        self.tokens.push(Token::BeginTag(name));

        for attribute in attributes {
            let mut content = try!(parser::parse_content(&attribute.value, &self.fragments)).into_iter();
            match content.next() {
                Some(ReturnType::Content(Content::String(text))) => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(text))),
                Some(ReturnType::Content(Content::Placeholder(name))) => {
                    self.reg_string(name.clone());
                    self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::Placeholder(name)));
                },
                Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
                Some(ReturnType::Scope(scope)) => {
                    self.reg_scope_vars(&scope);
                    self.tokens.push(Token::Scope(scope));
                },
                Some(ReturnType::End) => self.tokens.push(Token::End),
                None => self.tokens.push(Token::BeginAttribute(attribute.name.local, Content::String(String::new())))
            }

            for part in content {
                match part {
                    ReturnType::Content(Content::String(text)) => self.tokens.push(Token::AppendToAttribute(Content::String(text))),
                    ReturnType::Content(Content::Placeholder(name)) => {
                        self.reg_string(name.clone());
                        self.tokens.push(Token::AppendToAttribute(Content::Placeholder(name)));
                    },
                    ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                    ReturnType::Scope(scope) => {
                        self.reg_scope_vars(&scope);
                        self.tokens.push(Token::Scope(scope));
                    },
                    ReturnType::End => self.tokens.push(Token::End),
                }
            }

            self.tokens.push(Token::EndAttribute);
        }

        self.tokens.push(Token::EndTag(void || self_closing));

        Ok(())
    }

    fn add_text(&mut self, text: String) -> Result<(), Cow<'static, str>> {
        let mut content = try!(parser::parse_content(&text, &self.fragments)).into_iter();
        match content.next() {
            Some(ReturnType::Content(Content::String(text))) => self.tokens.push(Token::BeginText(Content::String(text))),
            Some(ReturnType::Content(Content::Placeholder(name))) => {
                self.reg_string(name.clone());
                self.tokens.push(Token::BeginText(Content::Placeholder(name)));
            },
            Some(ReturnType::Logic(_)) => return Err(Cow::Borrowed("logic can not be used as text")),
            Some(ReturnType::Scope(scope)) => {
                self.reg_scope_vars(&scope);
                self.tokens.push(Token::Scope(scope));
            },
            Some(ReturnType::End) => self.tokens.push(Token::End),
            None => return Ok(())
        }

        for part in content {
            match part {
                ReturnType::Content(Content::String(text)) => self.tokens.push(Token::AppendToText(Content::String(text))),
                ReturnType::Content(Content::Placeholder(name)) => {
                    self.reg_string(name.clone());
                    self.tokens.push(Token::AppendToText(Content::Placeholder(name)));
                },
                ReturnType::Logic(_) => return Err(Cow::Borrowed("logic can not be used as text")),
                ReturnType::Scope(scope) => {
                    self.reg_scope_vars(&scope);
                    self.tokens.push(Token::Scope(scope));
                },
                ReturnType::End => self.tokens.push(Token::End),
            }
        }
        self.tokens.push(Token::EndText);

        Ok(())
    }

    fn close_tag(&mut self, tag: Atom) {
        self.tokens.push(Token::CloseTag(tag));
    }

    fn reg_scope_vars(&mut self, scope: &Scope) {
        match scope {
            &Scope::If(ref logic) => logic.parameters(&mut |param| self.reg_bool(param.clone()))
        }
    }

    fn reg_string(&mut self, param: String) {
        match self.parameters.entry(param) {
            Entry::Occupied(mut entry) => match entry.get_mut() {
                &mut ContentType::String => {},
                entry => *entry = ContentType::OptionalString
            },
            Entry::Vacant(entry) => { entry.insert(ContentType::String); },
        }
    }

    fn reg_bool(&mut self, param: String) {
        match self.parameters.entry(param) {
            Entry::Occupied(mut entry) => match entry.get_mut() {
                &mut ContentType::Bool => {},
                entry => *entry = ContentType::OptionalString
            },
            Entry::Vacant(entry) => { entry.insert(ContentType::Bool); },
        }
    }
}

impl<'a, 'b: 'a> TokenSink for &'a mut Template<'b> {
    fn process_token(&mut self, token: HtmlToken) {
        match token {
            HtmlToken::TagToken(Tag {
                kind: TagKind::StartTag,
                name,
                attrs,
                self_closing
            }) => if let Err(e) = self.open_tag(name, attrs, self_closing) {
                self.errors.push(e);
            },
            HtmlToken::TagToken(Tag {
                kind: TagKind::EndTag,
                name,
                ..
            }) => self.close_tag(name),
            HtmlToken::CharacterTokens(text) => if let Err(e) = self.add_text(text) {
                self.errors.push(e);
            },

            HtmlToken::DoctypeToken(_) => {},
            HtmlToken::CommentToken(_) => {},
            HtmlToken::NullCharacterToken => {},
            HtmlToken::EOFToken => {},

            HtmlToken::ParseError(e) => self.errors.push(e)
        }
    }
}

// http://www.w3.org/TR/html5/syntax.html#void-elements
fn is_void(tag: &str) -> bool {
    match tag {
        "area" |
        "base" |
        "br" |
        "col" |
        "embed" |
        "hr" |
        "img" |
        "input" |
        "keygen" |
        "link" |
        "meta" |
        "param" |
        "source" |
        "track" |
        "wbr" => true,
        _ => false
    }
}

fn init_fragments<'a>() -> HashMap<&'static str, Box<Fragment + 'a>> {
    let mut map = HashMap::new();

    let f: Box<Fragment + 'a> = Box::new(fragments::If);
    map.insert(f.identifier(), f);

    let f = fragments::And;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Or;
    map.insert(f.identifier(), Box::new(f));

    let f = fragments::Not;
    map.insert(f.identifier(), Box::new(f));

    map
}<|endoftext|>


<commit_before>//! ### rust-mysql-simple
//! Mysql client library implemented in rust nightly.
//!
//! #### Install
//! Just include another `[dependencies.*]` section into your Cargo.toml:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! ```
//!
//! rust-mysql-simple offer support of SSL via `ssl` cargo feature which is enabled by default. If you have no plans to use SSL, then you should disable that feature to not to depend on rust-openssl:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! default-features = false
//! ```
//!
//! #### Use
//! You should start by creating [`MyOpts`](conn/struct.MyOpts.html) struct.
//!
//! Then you can create [`MyPool`](conn/pool/struct.MyPool.html) which should be
//! enough to work with mysql server.
#![crate_name="mysql"]
#![crate_type="rlib"]
#![crate_type="dylib"]

#![feature(plugin)]
extern crate time;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate regex;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate unix_socket;

mod scramble;
pub mod consts;
pub mod error;
mod packet;
mod io;
pub mod value;
pub mod conn;
<commit_msg>Drop plugin feature<commit_after>//! ### rust-mysql-simple
//! Mysql client library implemented in rust nightly.
//!
//! #### Install
//! Just include another `[dependencies.*]` section into your Cargo.toml:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! ```
//!
//! rust-mysql-simple offer support of SSL via `ssl` cargo feature which is enabled by default. If you have no plans to use SSL, then you should disable that feature to not to depend on rust-openssl:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! default-features = false
//! ```
//!
//! #### Use
//! You should start by creating [`MyOpts`](conn/struct.MyOpts.html) struct.
//!
//! Then you can create [`MyPool`](conn/pool/struct.MyPool.html) which should be
//! enough to work with mysql server.
#![crate_name="mysql"]
#![crate_type="rlib"]
#![crate_type="dylib"]

extern crate time;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate regex;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate unix_socket;

mod scramble;
pub mod consts;
pub mod error;
mod packet;
mod io;
pub mod value;
pub mod conn;
<|endoftext|>