<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * Unicode-intensive `char` methods.
 *
 * These methods implement functionality for `char` that requires knowledge of
 * Unicode definitions, including normalization, categorization, and display information.
 */

use core::option::Option;
use tables::{derived_property, property, general_category, conversions, charwidth};

/// Returns whether the specified `char` is considered a Unicode alphabetic
/// code point
pub fn is_alphabetic(c: char) -> bool {
    match c {
        'a' ... 'z' | 'A' ... 'Z' => true,
        c if c > '\x7f' => derived_property::Alphabetic(c),
        _ => false
    }
}

/// Returns whether the specified `char` satisfies the 'XID_Start' Unicode property
///
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
#[allow(non_snake_case)]
pub fn is_XID_start(c: char) -> bool    { derived_property::XID_Start(c) }

/// Returns whether the specified `char` satisfies the 'XID_Continue' Unicode property
///
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
#[allow(non_snake_case)]
pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) }

///
/// Indicates whether a `char` is in lower case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Lowercase'.
///
#[inline]
pub fn is_lowercase(c: char) -> bool {
    match c {
        'a' ... 'z' => true,
        c if c > '\x7f' => derived_property::Lowercase(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is in upper case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Uppercase'.
///
#[inline]
pub fn is_uppercase(c: char) -> bool {
    match c {
        'A' ... 'Z' => true,
        c if c > '\x7f' => derived_property::Uppercase(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is whitespace
///
/// Whitespace is defined in terms of the Unicode Property 'White_Space'.
///
#[inline]
pub fn is_whitespace(c: char) -> bool {
    match c {
        ' ' | '\x09' ... '\x0d' => true,
        c if c > '\x7f' => property::White_Space(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is alphanumeric
///
/// Alphanumericness is defined in terms of the Unicode General Categories
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
///
#[inline]
pub fn is_alphanumeric(c: char) -> bool {
    is_alphabetic(c)
        || is_digit(c)
}

///
/// Indicates whether a `char` is a control code point
///
/// Control code points are defined in terms of the Unicode General Category
/// 'Cc'.
///
#[inline]
pub fn is_control(c: char) -> bool { general_category::Cc(c) }

/// Indicates whether the `char` is numeric (Nd, Nl, or No)
#[inline]
pub fn is_digit(c: char) -> bool {
    match c {
        '0' ... '9' => true,
        c if c > '\x7f' => general_category::N(c),
        _ => false
    }
}

/// Convert a char to its uppercase equivalent
///
/// The case-folding performed is the common or simple mapping:
/// it maps one Unicode codepoint (one char in Rust) to its uppercase equivalent according
/// to the Unicode database at ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
/// The additional SpecialCasing.txt is not considered here, as it expands to multiple
/// codepoints in some cases.
///
/// A full reference can be found here
/// http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
///
/// # Return value
///
/// Returns the char itself if no conversion was made
#[inline]
pub fn to_uppercase(c: char) -> char {
    conversions::to_upper(c)
}

/// Convert a char to its lowercase equivalent
///
/// The case-folding performed is the common or simple mapping
/// see `to_uppercase` for references and more information
///
/// # Return value
///
/// Returns the char itself if no conversion if possible
#[inline]
pub fn to_lowercase(c: char) -> char {
    conversions::to_lower(c)
}

/// Returns this character's displayed width in columns, or `None` if it is a
/// control character other than `'\x00'`.
///
/// `is_cjk` determines behavior for characters in the Ambiguous category:
/// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
/// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
/// recommends that these characters be treated as 1 column (i.e.,
/// `is_cjk` = `false`) if the context cannot be reliably determined.
pub fn width(c: char, is_cjk: bool) -> Option<uint> {
    charwidth::width(c, is_cjk)
}

/// Useful functions for Unicode characters.
pub trait UnicodeChar {
    /// Returns whether the specified character is considered a Unicode
    /// alphabetic code point.
    fn is_alphabetic(&self) -> bool;

    /// Returns whether the specified character satisfies the 'XID_Start'
    /// Unicode property.
    ///
    /// 'XID_Start' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to ID_Start but modified for closure under NFKx.
    #[allow(non_snake_case)]
    fn is_XID_start(&self) -> bool;

    /// Returns whether the specified `char` satisfies the 'XID_Continue'
    /// Unicode property.
    ///
    /// 'XID_Continue' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to 'ID_Continue' but modified for closure under NFKx.
    #[allow(non_snake_case)]
    fn is_XID_continue(&self) -> bool;

    /// Indicates whether a character is in lowercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Lowercase`.
    fn is_lowercase(&self) -> bool;

    /// Indicates whether a character is in uppercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Uppercase`.
    fn is_uppercase(&self) -> bool;

    /// Indicates whether a character is whitespace.
    ///
    /// Whitespace is defined in terms of the Unicode Property `White_Space`.
    fn is_whitespace(&self) -> bool;

    /// Indicates whether a character is alphanumeric.
    ///
    /// Alphanumericness is defined in terms of the Unicode General Categories
    /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
    fn is_alphanumeric(&self) -> bool;

    /// Indicates whether a character is a control code point.
    ///
    /// Control code points are defined in terms of the Unicode General
    /// Category `Cc`.
    fn is_control(&self) -> bool;

    /// Indicates whether the character is numeric (Nd, Nl, or No).
    fn is_digit(&self) -> bool;

    /// Converts a character to its lowercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping. See
    /// `to_uppercase()` for references and more information.
    ///
    /// # Return value
    ///
    /// Returns the lowercase equivalent of the character, or the character
    /// itself if no conversion is possible.
    fn to_lowercase(&self) -> char;

    /// Converts a character to its uppercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping: it maps
    /// one Unicode codepoint (one character in Rust) to its uppercase
    /// equivalent according to the Unicode database [1]. The additional
    /// `SpecialCasing.txt` is not considered here, as it expands to multiple
    /// codepoints in some cases.
    ///
    /// A full reference can be found here [2].
    ///
    /// # Return value
    ///
    /// Returns the uppercase equivalent of the character, or the character
    /// itself if no conversion was made.
    ///
    /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
    ///
    /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
    fn to_uppercase(&self) -> char;

    /// Returns this character's displayed width in columns, or `None` if it is a
    /// control character other than `'\x00'`.
    ///
    /// `is_cjk` determines behavior for characters in the Ambiguous category:
    /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
    /// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
    /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
    /// recommends that these characters be treated as 1 column (i.e.,
    /// `is_cjk` = `false`) if the context cannot be reliably determined.
    fn width(&self, is_cjk: bool) -> Option<uint>;
}

impl UnicodeChar for char {
    fn is_alphabetic(&self) -> bool { is_alphabetic(*self) }

    fn is_XID_start(&self) -> bool { is_XID_start(*self) }

    fn is_XID_continue(&self) -> bool { is_XID_continue(*self) }

    fn is_lowercase(&self) -> bool { is_lowercase(*self) }

    fn is_uppercase(&self) -> bool { is_uppercase(*self) }

    fn is_whitespace(&self) -> bool { is_whitespace(*self) }

    fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) }

    fn is_control(&self) -> bool { is_control(*self) }

    fn is_digit(&self) -> bool { is_digit(*self) }

    fn to_lowercase(&self) -> char { to_lowercase(*self) }

    fn to_uppercase(&self) -> char { to_uppercase(*self) }

    fn width(&self, is_cjk: bool) -> Option<uint> { width(*self, is_cjk) }
}
<commit_msg>Link to Unicode SpecialCasing.txt document<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * Unicode-intensive `char` methods.
 *
 * These methods implement functionality for `char` that requires knowledge of
 * Unicode definitions, including normalization, categorization, and display information.
 */

use core::option::Option;
use tables::{derived_property, property, general_category, conversions, charwidth};

/// Returns whether the specified `char` is considered a Unicode alphabetic
/// code point
pub fn is_alphabetic(c: char) -> bool {
    match c {
        'a' ... 'z' | 'A' ... 'Z' => true,
        c if c > '\x7f' => derived_property::Alphabetic(c),
        _ => false
    }
}

/// Returns whether the specified `char` satisfies the 'XID_Start' Unicode property
///
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
#[allow(non_snake_case)]
pub fn is_XID_start(c: char) -> bool    { derived_property::XID_Start(c) }

/// Returns whether the specified `char` satisfies the 'XID_Continue' Unicode property
///
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
#[allow(non_snake_case)]
pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) }

///
/// Indicates whether a `char` is in lower case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Lowercase'.
///
#[inline]
pub fn is_lowercase(c: char) -> bool {
    match c {
        'a' ... 'z' => true,
        c if c > '\x7f' => derived_property::Lowercase(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is in upper case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Uppercase'.
///
#[inline]
pub fn is_uppercase(c: char) -> bool {
    match c {
        'A' ... 'Z' => true,
        c if c > '\x7f' => derived_property::Uppercase(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is whitespace
///
/// Whitespace is defined in terms of the Unicode Property 'White_Space'.
///
#[inline]
pub fn is_whitespace(c: char) -> bool {
    match c {
        ' ' | '\x09' ... '\x0d' => true,
        c if c > '\x7f' => property::White_Space(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is alphanumeric
///
/// Alphanumericness is defined in terms of the Unicode General Categories
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
///
#[inline]
pub fn is_alphanumeric(c: char) -> bool {
    is_alphabetic(c)
        || is_digit(c)
}

///
/// Indicates whether a `char` is a control code point
///
/// Control code points are defined in terms of the Unicode General Category
/// 'Cc'.
///
#[inline]
pub fn is_control(c: char) -> bool { general_category::Cc(c) }

/// Indicates whether the `char` is numeric (Nd, Nl, or No)
#[inline]
pub fn is_digit(c: char) -> bool {
    match c {
        '0' ... '9' => true,
        c if c > '\x7f' => general_category::N(c),
        _ => false
    }
}

/// Convert a char to its uppercase equivalent
///
/// The case-folding performed is the common or simple mapping:
/// it maps one Unicode codepoint (one char in Rust) to its uppercase equivalent according
/// to the Unicode database at ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
/// The additional SpecialCasing.txt is not considered here, as it expands to multiple
/// codepoints in some cases.
///
/// A full reference can be found here
/// http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
///
/// # Return value
///
/// Returns the char itself if no conversion was made
#[inline]
pub fn to_uppercase(c: char) -> char {
    conversions::to_upper(c)
}

/// Convert a char to its lowercase equivalent
///
/// The case-folding performed is the common or simple mapping
/// see `to_uppercase` for references and more information
///
/// # Return value
///
/// Returns the char itself if no conversion if possible
#[inline]
pub fn to_lowercase(c: char) -> char {
    conversions::to_lower(c)
}

/// Returns this character's displayed width in columns, or `None` if it is a
/// control character other than `'\x00'`.
///
/// `is_cjk` determines behavior for characters in the Ambiguous category:
/// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
/// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
/// recommends that these characters be treated as 1 column (i.e.,
/// `is_cjk` = `false`) if the context cannot be reliably determined.
pub fn width(c: char, is_cjk: bool) -> Option<uint> {
    charwidth::width(c, is_cjk)
}

/// Useful functions for Unicode characters.
pub trait UnicodeChar {
    /// Returns whether the specified character is considered a Unicode
    /// alphabetic code point.
    fn is_alphabetic(&self) -> bool;

    /// Returns whether the specified character satisfies the 'XID_Start'
    /// Unicode property.
    ///
    /// 'XID_Start' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to ID_Start but modified for closure under NFKx.
    #[allow(non_snake_case)]
    fn is_XID_start(&self) -> bool;

    /// Returns whether the specified `char` satisfies the 'XID_Continue'
    /// Unicode property.
    ///
    /// 'XID_Continue' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to 'ID_Continue' but modified for closure under NFKx.
    #[allow(non_snake_case)]
    fn is_XID_continue(&self) -> bool;

    /// Indicates whether a character is in lowercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Lowercase`.
    fn is_lowercase(&self) -> bool;

    /// Indicates whether a character is in uppercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Uppercase`.
    fn is_uppercase(&self) -> bool;

    /// Indicates whether a character is whitespace.
    ///
    /// Whitespace is defined in terms of the Unicode Property `White_Space`.
    fn is_whitespace(&self) -> bool;

    /// Indicates whether a character is alphanumeric.
    ///
    /// Alphanumericness is defined in terms of the Unicode General Categories
    /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
    fn is_alphanumeric(&self) -> bool;

    /// Indicates whether a character is a control code point.
    ///
    /// Control code points are defined in terms of the Unicode General
    /// Category `Cc`.
    fn is_control(&self) -> bool;

    /// Indicates whether the character is numeric (Nd, Nl, or No).
    fn is_digit(&self) -> bool;

    /// Converts a character to its lowercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping. See
    /// `to_uppercase()` for references and more information.
    ///
    /// # Return value
    ///
    /// Returns the lowercase equivalent of the character, or the character
    /// itself if no conversion is possible.
    fn to_lowercase(&self) -> char;

    /// Converts a character to its uppercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping: it maps
    /// one Unicode codepoint (one character in Rust) to its uppercase
    /// equivalent according to the Unicode database [1]. The additional
    /// [`SpecialCasing.txt`] is not considered here, as it expands to multiple
    /// codepoints in some cases.
    ///
    /// A full reference can be found here [2].
    ///
    /// # Return value
    ///
    /// Returns the uppercase equivalent of the character, or the character
    /// itself if no conversion was made.
    ///
    /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
    ///
    /// [`SpecialCasing`.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
    ///
    /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
    fn to_uppercase(&self) -> char;

    /// Returns this character's displayed width in columns, or `None` if it is a
    /// control character other than `'\x00'`.
    ///
    /// `is_cjk` determines behavior for characters in the Ambiguous category:
    /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
    /// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
    /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
    /// recommends that these characters be treated as 1 column (i.e.,
    /// `is_cjk` = `false`) if the context cannot be reliably determined.
    fn width(&self, is_cjk: bool) -> Option<uint>;
}

impl UnicodeChar for char {
    fn is_alphabetic(&self) -> bool { is_alphabetic(*self) }

    fn is_XID_start(&self) -> bool { is_XID_start(*self) }

    fn is_XID_continue(&self) -> bool { is_XID_continue(*self) }

    fn is_lowercase(&self) -> bool { is_lowercase(*self) }

    fn is_uppercase(&self) -> bool { is_uppercase(*self) }

    fn is_whitespace(&self) -> bool { is_whitespace(*self) }

    fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) }

    fn is_control(&self) -> bool { is_control(*self) }

    fn is_digit(&self) -> bool { is_digit(*self) }

    fn to_lowercase(&self) -> char { to_lowercase(*self) }

    fn to_uppercase(&self) -> char { to_uppercase(*self) }

    fn width(&self, is_cjk: bool) -> Option<uint> { width(*self, is_cjk) }
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::ops::Deref;
use std::rc::Rc;

use baseline::fct::{Bailouts, BailoutInfo, CatchType, Comments, Comment, ExHandler, JitFct,
                    LineNumberTable, GcPoints, GcPoint};
use baseline::codegen::CondCode;
use byteorder::{LittleEndian, WriteBytesExt};
use cpu::{Reg, SCRATCH};
use ctxt::FctId;
use dseg::DSeg;
use lexer::position::Position;
use os::signal::Trap;
use ty::MachineMode;

#[cfg(target_arch = "x86_64")]
pub use self::x64::*;

#[cfg(target_arch = "x86_64")]
pub mod x64;

#[cfg(target_arch = "aarch64")]
pub use self::arm64::*;

#[cfg(target_arch = "aarch64")]
pub mod arm64;

pub struct MacroAssembler {
    data: Vec<u8>,
    labels: Vec<Option<usize>>,
    jumps: Vec<ForwardJump>,
    bailouts: Vec<(Label, Trap, Position)>,
    bailout_infos: Bailouts,
    dseg: DSeg,
    gcpoints: GcPoints,
    comments: Comments,
    linenos: LineNumberTable,
    exception_handlers: Vec<ExHandler>,
    scratch_registers: ScratchRegisters,
}

impl MacroAssembler {
    pub fn new() -> MacroAssembler {
        MacroAssembler {
            data: Vec::new(),
            labels: Vec::new(),
            jumps: Vec::new(),
            bailouts: Vec::new(),
            bailout_infos: Bailouts::new(),
            dseg: DSeg::new(),
            gcpoints: GcPoints::new(),
            comments: Comments::new(),
            linenos: LineNumberTable::new(),
            exception_handlers: Vec::new(),
            scratch_registers: ScratchRegisters::new(),
        }
    }

    pub fn jit(mut self, id: FctId, stacksize: i32) -> JitFct {
        self.finish();

        JitFct::from_buffer(id,
                            &self.dseg,
                            &self.data,
                            self.bailout_infos,
                            self.gcpoints,
                            stacksize,
                            self.comments,
                            self.linenos,
                            self.exception_handlers)
    }

    pub fn data(mut self) -> Vec<u8> {
        self.finish();

        self.data
    }

    fn finish(&mut self) {
        let bailouts = self.bailouts.drain(0..).collect::<Vec<_>>();

        for bailout in &bailouts {
            let (lbl, trap, pos) = *bailout;

            self.bind_label(lbl);
            self.emit_lineno(pos.line as i32);
            self.trap(trap);
        }

        self.fix_forward_jumps();
    }

    pub fn add_addr(&mut self, ptr: *const u8) -> i32 {
        self.dseg.add_addr(ptr)
    }

    pub fn pos(&self) -> usize {
        self.data.len()
    }

    pub fn test_if_nil_bailout(&mut self, pos: Position, reg: Reg, trap: Trap) {
        let lbl = self.test_if_nil(reg);
        self.emit_bailout(lbl, trap, pos);
    }

    pub fn test_if_nil(&mut self, reg: Reg) -> Label {
        self.cmp_zero(MachineMode::Ptr, reg);

        let lbl = self.create_label();
        self.jump_if(CondCode::Equal, lbl);

        lbl
    }

    pub fn emit_lineno(&mut self, lineno: i32) {
        let pos = self.pos() as i32;
        self.linenos.insert(pos, lineno);
    }

    pub fn emit_gcpoint(&mut self, gcpoint: GcPoint) {
        let pos = self.pos() as i32;
        self.gcpoints.insert(pos, gcpoint);
    }

    pub fn emit_bailout_info(&mut self, info: BailoutInfo) {
        let pos = self.pos() as i32;
        self.bailout_infos.insert(pos, info);
    }

    pub fn create_label(&mut self) -> Label {
        let idx = self.labels.len();
        self.labels.push(None);

        Label(idx)
    }

    pub fn emit_comment(&mut self, comment: Comment) {
        let pos = self.pos() as i32;
        self.comments.insert(pos, comment);
    }

    pub fn bind_label(&mut self, lbl: Label) {
        let lbl_idx = lbl.index();

        assert!(self.labels[lbl_idx].is_none());
        self.labels[lbl_idx] = Some(self.pos());
    }

    pub fn emit_bailout(&mut self, lbl: Label, trap: Trap, pos: Position) {
        self.bailouts.push((lbl, trap, pos));
    }

    pub fn emit_bailout_inplace(&mut self, trap: Trap, pos: Position) {
        self.emit_lineno(pos.line as i32);
        self.trap(trap);
    }

    pub fn emit_exception_handler(&mut self,
                                  span: (usize, usize),
                                  catch: usize,
                                  offset: Option<i32>,
                                  catch_type: CatchType) {
        self.exception_handlers.push(ExHandler {
            try_start: span.0,
            try_end: span.1,
            catch: catch,
            offset: offset,
            catch_type: catch_type,
        });
    }

    pub fn get_scratch(&self) -> ScratchReg {
        self.scratch_registers.get()
    }

    pub fn emit_u8(&mut self, value: u8) {
        self.data.write_u8(value).unwrap();
    }

    pub fn emit_u32(&mut self, value: u32) {
        self.data.write_u32::<LittleEndian>(value).unwrap();
    }
}

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

impl Label {
    pub fn index(&self) -> usize {
        self.0
    }
}

#[derive(Clone, Debug)]
pub struct ScratchRegisters {
    regs: &'static [Reg],
    value: Rc<Cell<u32>>,
}

impl ScratchRegisters {
    pub fn new() -> ScratchRegisters {
        ScratchRegisters {
            regs: &SCRATCH,
            value: Rc::new(Cell::new(0))
        }
    }

    #[cfg(test)]
    pub fn with_regs(regs: &'static [Reg]) -> ScratchRegisters {
        ScratchRegisters {
            regs: regs,
            value: Rc::new(Cell::new(0))
        }
    }

    pub fn get(&self) -> ScratchReg {
        let value = self.value.get();

        for (ind, &reg) in self.regs.iter().enumerate() {
            if (value >> ind) & 1 == 0 {
                let bitmask = 1 << ind;
                self.value.set(value | bitmask);

                return ScratchReg {
                    ind: ind as u32,
                    reg: reg,
                    scratch: self.clone(),
                };
            }
        }

        panic!("all scratch registers used");
    }

    fn free(&self, reg: &ScratchReg) {
        let value = self.value.get();
        let bitmask = !(1 << reg.ind);

        self.value.set(value & bitmask);
    }
}

#[derive(Debug)]
pub struct ScratchReg {
    ind: u32,
    reg: Reg,
    scratch: ScratchRegisters,
}

impl ScratchReg {
    pub fn reg(&self) -> Reg {
        self.reg
    }
}

impl Drop for ScratchReg {
    fn drop(&mut self) {
        self.scratch.free(self);
    }
}

impl Deref for ScratchReg {
    type Target = Reg;

    fn deref(&self) -> &Reg {
        &self.reg
    }
}

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

    #[test]
    fn test_label() {
        let mut masm = MacroAssembler::new();

        assert_eq!(Label(0), masm.create_label());
        assert_eq!(Label(1), masm.create_label());
    }

    #[test]
    #[should_panic]
    fn test_bind_label_twice() {
        let mut masm = MacroAssembler::new();
        let lbl = masm.create_label();

        masm.bind_label(lbl);
        masm.bind_label(lbl);
    }

    static SCRATCH_REGS1: [Reg; 1] = [Reg(0)];
    static SCRATCH_REGS2: [Reg; 1] = [Reg(1)];

    #[test]
    #[should_panic]
    #[allow(unused_variables)]
    fn test_scratch_fail() {
        let masm = ScratchRegisters::with_regs(&SCRATCH_REGS1);

        let scratch1 = masm.get();
        let scratch2 = masm.get();
    }

    #[test]
    fn test_scratch_drop() {
        let masm = ScratchRegisters::with_regs(&SCRATCH_REGS2);

        {
            let scratch1 = masm.get();
            assert_eq!(*scratch1, Reg(1));
        }

        {
            let scratch1 = masm.get();
            assert_eq!(*scratch1, Reg(1));
        }
    }
}
<commit_msg>added test for multiple scratch registers<commit_after>use std::cell::Cell;
use std::ops::Deref;
use std::rc::Rc;

use baseline::fct::{Bailouts, BailoutInfo, CatchType, Comments, Comment, ExHandler, JitFct,
                    LineNumberTable, GcPoints, GcPoint};
use baseline::codegen::CondCode;
use byteorder::{LittleEndian, WriteBytesExt};
use cpu::{Reg, SCRATCH};
use ctxt::FctId;
use dseg::DSeg;
use lexer::position::Position;
use os::signal::Trap;
use ty::MachineMode;

#[cfg(target_arch = "x86_64")]
pub use self::x64::*;

#[cfg(target_arch = "x86_64")]
pub mod x64;

#[cfg(target_arch = "aarch64")]
pub use self::arm64::*;

#[cfg(target_arch = "aarch64")]
pub mod arm64;

pub struct MacroAssembler {
    data: Vec<u8>,
    labels: Vec<Option<usize>>,
    jumps: Vec<ForwardJump>,
    bailouts: Vec<(Label, Trap, Position)>,
    bailout_infos: Bailouts,
    dseg: DSeg,
    gcpoints: GcPoints,
    comments: Comments,
    linenos: LineNumberTable,
    exception_handlers: Vec<ExHandler>,
    scratch_registers: ScratchRegisters,
}

impl MacroAssembler {
    pub fn new() -> MacroAssembler {
        MacroAssembler {
            data: Vec::new(),
            labels: Vec::new(),
            jumps: Vec::new(),
            bailouts: Vec::new(),
            bailout_infos: Bailouts::new(),
            dseg: DSeg::new(),
            gcpoints: GcPoints::new(),
            comments: Comments::new(),
            linenos: LineNumberTable::new(),
            exception_handlers: Vec::new(),
            scratch_registers: ScratchRegisters::new(),
        }
    }

    pub fn jit(mut self, id: FctId, stacksize: i32) -> JitFct {
        self.finish();

        JitFct::from_buffer(id,
                            &self.dseg,
                            &self.data,
                            self.bailout_infos,
                            self.gcpoints,
                            stacksize,
                            self.comments,
                            self.linenos,
                            self.exception_handlers)
    }

    pub fn data(mut self) -> Vec<u8> {
        self.finish();

        self.data
    }

    fn finish(&mut self) {
        let bailouts = self.bailouts.drain(0..).collect::<Vec<_>>();

        for bailout in &bailouts {
            let (lbl, trap, pos) = *bailout;

            self.bind_label(lbl);
            self.emit_lineno(pos.line as i32);
            self.trap(trap);
        }

        self.fix_forward_jumps();
    }

    pub fn add_addr(&mut self, ptr: *const u8) -> i32 {
        self.dseg.add_addr(ptr)
    }

    pub fn pos(&self) -> usize {
        self.data.len()
    }

    pub fn test_if_nil_bailout(&mut self, pos: Position, reg: Reg, trap: Trap) {
        let lbl = self.test_if_nil(reg);
        self.emit_bailout(lbl, trap, pos);
    }

    pub fn test_if_nil(&mut self, reg: Reg) -> Label {
        self.cmp_zero(MachineMode::Ptr, reg);

        let lbl = self.create_label();
        self.jump_if(CondCode::Equal, lbl);

        lbl
    }

    pub fn emit_lineno(&mut self, lineno: i32) {
        let pos = self.pos() as i32;
        self.linenos.insert(pos, lineno);
    }

    pub fn emit_gcpoint(&mut self, gcpoint: GcPoint) {
        let pos = self.pos() as i32;
        self.gcpoints.insert(pos, gcpoint);
    }

    pub fn emit_bailout_info(&mut self, info: BailoutInfo) {
        let pos = self.pos() as i32;
        self.bailout_infos.insert(pos, info);
    }

    pub fn create_label(&mut self) -> Label {
        let idx = self.labels.len();
        self.labels.push(None);

        Label(idx)
    }

    pub fn emit_comment(&mut self, comment: Comment) {
        let pos = self.pos() as i32;
        self.comments.insert(pos, comment);
    }

    pub fn bind_label(&mut self, lbl: Label) {
        let lbl_idx = lbl.index();

        assert!(self.labels[lbl_idx].is_none());
        self.labels[lbl_idx] = Some(self.pos());
    }

    pub fn emit_bailout(&mut self, lbl: Label, trap: Trap, pos: Position) {
        self.bailouts.push((lbl, trap, pos));
    }

    pub fn emit_bailout_inplace(&mut self, trap: Trap, pos: Position) {
        self.emit_lineno(pos.line as i32);
        self.trap(trap);
    }

    pub fn emit_exception_handler(&mut self,
                                  span: (usize, usize),
                                  catch: usize,
                                  offset: Option<i32>,
                                  catch_type: CatchType) {
        self.exception_handlers.push(ExHandler {
            try_start: span.0,
            try_end: span.1,
            catch: catch,
            offset: offset,
            catch_type: catch_type,
        });
    }

    pub fn get_scratch(&self) -> ScratchReg {
        self.scratch_registers.get()
    }

    pub fn emit_u8(&mut self, value: u8) {
        self.data.write_u8(value).unwrap();
    }

    pub fn emit_u32(&mut self, value: u32) {
        self.data.write_u32::<LittleEndian>(value).unwrap();
    }
}

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

impl Label {
    pub fn index(&self) -> usize {
        self.0
    }
}

#[derive(Clone, Debug)]
pub struct ScratchRegisters {
    regs: &'static [Reg],
    value: Rc<Cell<u32>>,
}

impl ScratchRegisters {
    pub fn new() -> ScratchRegisters {
        ScratchRegisters {
            regs: &SCRATCH,
            value: Rc::new(Cell::new(0))
        }
    }

    #[cfg(test)]
    pub fn with_regs(regs: &'static [Reg]) -> ScratchRegisters {
        ScratchRegisters {
            regs: regs,
            value: Rc::new(Cell::new(0))
        }
    }

    pub fn get(&self) -> ScratchReg {
        let value = self.value.get();

        for (ind, &reg) in self.regs.iter().enumerate() {
            if (value >> ind) & 1 == 0 {
                let bitmask = 1 << ind;
                self.value.set(value | bitmask);

                return ScratchReg {
                    ind: ind as u32,
                    reg: reg,
                    scratch: self.clone(),
                };
            }
        }

        panic!("all scratch registers used");
    }

    fn free(&self, reg: &ScratchReg) {
        let value = self.value.get();
        let bitmask = !(1 << reg.ind);

        self.value.set(value & bitmask);
    }
}

#[derive(Debug)]
pub struct ScratchReg {
    ind: u32,
    reg: Reg,
    scratch: ScratchRegisters,
}

impl ScratchReg {
    pub fn reg(&self) -> Reg {
        self.reg
    }
}

impl Drop for ScratchReg {
    fn drop(&mut self) {
        self.scratch.free(self);
    }
}

impl Deref for ScratchReg {
    type Target = Reg;

    fn deref(&self) -> &Reg {
        &self.reg
    }
}

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

    #[test]
    fn test_label() {
        let mut masm = MacroAssembler::new();

        assert_eq!(Label(0), masm.create_label());
        assert_eq!(Label(1), masm.create_label());
    }

    #[test]
    #[should_panic]
    fn test_bind_label_twice() {
        let mut masm = MacroAssembler::new();
        let lbl = masm.create_label();

        masm.bind_label(lbl);
        masm.bind_label(lbl);
    }

    static SCRATCH_REGS1: [Reg; 1] = [Reg(0)];
    static SCRATCH_REGS2: [Reg; 1] = [Reg(1)];
    static SCRATCH_REGS3: [Reg; 3] = [Reg(2), Reg(3), Reg(4)];

    #[test]
    #[should_panic]
    #[allow(unused_variables)]
    fn test_scratch_fail() {
        let masm = ScratchRegisters::with_regs(&SCRATCH_REGS1);

        let scratch1 = masm.get();
        let scratch2 = masm.get();
    }

    #[test]
    fn tets_scratch_multiple() {
        let masm = ScratchRegisters::with_regs(&SCRATCH_REGS3);

        let scratch1 = masm.get();
        let scratch2 = masm.get();

        assert_eq!(*scratch1, Reg(2));
        assert_eq!(*scratch2, Reg(3));

        {
            let scratch3 = masm.get();
            assert_eq!(*scratch3, Reg(4));
        }

        let scratch3 = masm.get();
        assert_eq!(*scratch3, Reg(4));
    }

    #[test]
    fn test_scratch_drop() {
        let masm = ScratchRegisters::with_regs(&SCRATCH_REGS2);

        {
            let scratch1 = masm.get();
            assert_eq!(*scratch1, Reg(1));
        }

        {
            let scratch1 = masm.get();
            assert_eq!(*scratch1, Reg(1));
        }
    }
}
<|endoftext|>


<commit_before>/*
Module: deque

A deque.  Untested as of yet.  Likely buggy.
*/

/*
Object: t
*/
type t<T> = obj {
    // Method: size
    fn size() -> uint;
    // Method: add_front
    fn add_front(T);
    // Method: add_back
    fn add_back(T);
    // Method: pop_front
    fn pop_front() -> T;
    // Method: pop_back
    fn pop_back() -> T;
    // Method: peek_front
    fn peek_front() -> T;
    // Method: peek_back
    fn peek_back() -> T;
    // Method: get
    fn get(int) -> T;
    };

/*
Section: Functions
*/

/*
Function: create
*/
fn create<T: copy>() -> t<T> {
    type cell<T> = option::t<T>;

    let initial_capacity: uint = 32u; // 2^5
     /**
      * Grow is only called on full elts, so nelts is also len(elts), unlike
      * elsewhere.
      */
    fn grow<T: copy>(nelts: uint, lo: uint, elts: [mutable cell<T>]) ->
       [mutable cell<T>] {
        assert (nelts == vec::len(elts));
        let rv = [mutable];

        let i = 0u;
        let nalloc = uint::next_power_of_two(nelts + 1u);
        while i < nalloc {
            if i < nelts {
                rv += [mutable elts[(lo + i) % nelts]];
            } else { rv += [mutable option::none]; }
            i += 1u;
        }

        ret rv;
    }
    fn get<T: copy>(elts: [mutable cell<T>], i: uint) -> T {
        ret alt elts[i] { option::some(t) { t } _ { fail } };
    }
    obj deque<T: copy>(mutable nelts: uint,
                      mutable lo: uint,
                      mutable hi: uint,
                      mutable elts: [mutable cell<T>]) {
        fn size() -> uint { ret nelts; }
        fn add_front(t: T) {
            let oldlo: uint = lo;
            if lo == 0u {
                lo = vec::len::<cell<T>>(elts) - 1u;
            } else { lo -= 1u; }
            if lo == hi {
                elts = grow::<T>(nelts, oldlo, elts);
                lo = vec::len::<cell<T>>(elts) - 1u;
                hi = nelts;
            }
            elts[lo] = option::some::<T>(t);
            nelts += 1u;
        }
        fn add_back(t: T) {
            if lo == hi && nelts != 0u {
                elts = grow::<T>(nelts, lo, elts);
                lo = 0u;
                hi = nelts;
            }
            elts[hi] = option::some::<T>(t);
            hi = (hi + 1u) % vec::len::<cell<T>>(elts);
            nelts += 1u;
        }

        /**
         * We actually release (turn to none()) the T we're popping so
         * that we don't keep anyone's refcount up unexpectedly.
         */
        fn pop_front() -> T {
            let t: T = get::<T>(elts, lo);
            elts[lo] = option::none::<T>;
            lo = (lo + 1u) % vec::len::<cell<T>>(elts);
            nelts -= 1u;
            ret t;
        }
        fn pop_back() -> T {
            if hi == 0u {
                hi = vec::len::<cell<T>>(elts) - 1u;
            } else { hi -= 1u; }
            let t: T = get::<T>(elts, hi);
            elts[hi] = option::none::<T>;
            nelts -= 1u;
            ret t;
        }
        fn peek_front() -> T { ret get::<T>(elts, lo); }
        fn peek_back() -> T { ret get::<T>(elts, hi - 1u); }
        fn get(i: int) -> T {
            let idx: uint = (lo + (i as uint)) % vec::len::<cell<T>>(elts);
            ret get::<T>(elts, idx);
        }
    }
    let v: [mutable cell<T>] =
        vec::init_elt_mut(option::none, initial_capacity);
    ret deque::<T>(0u, 0u, 0u, v);
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Convert std::deque over to an iface<commit_after>import option::{some, none};

/*
Module: deque

A deque.  Untested as of yet.  Likely buggy.
*/

/*
Iface: t
*/
iface t<T> {
    // Method: size
    fn size() -> uint;
    // Method: add_front
    fn add_front(T);
    // Method: add_back
    fn add_back(T);
    // Method: pop_front
    fn pop_front() -> T;
    // Method: pop_back
    fn pop_back() -> T;
    // Method: peek_front
    fn peek_front() -> T;
    // Method: peek_back
    fn peek_back() -> T;
    // Method: get
    fn get(int) -> T;
}

/*
Section: Functions
*/

/*
Function: create
*/
// FIXME eventually, a proper datatype plus an exported impl would be
// preferrable
fn create<T: copy>() -> t<T> {
    type cell<T> = option::t<T>;

    let initial_capacity: uint = 32u; // 2^5
     /**
      * Grow is only called on full elts, so nelts is also len(elts), unlike
      * elsewhere.
      */
    fn grow<T: copy>(nelts: uint, lo: uint, elts: [mutable cell<T>]) ->
       [mutable cell<T>] {
        assert (nelts == vec::len(elts));
        let rv = [mutable];

        let i = 0u;
        let nalloc = uint::next_power_of_two(nelts + 1u);
        while i < nalloc {
            if i < nelts {
                rv += [mutable elts[(lo + i) % nelts]];
            } else { rv += [mutable none]; }
            i += 1u;
        }

        ret rv;
    }
    fn get<T: copy>(elts: [mutable cell<T>], i: uint) -> T {
        ret alt elts[i] { some(t) { t } _ { fail } };
    }

    type repr<T> = {mutable nelts: uint,
                    mutable lo: uint,
                    mutable hi: uint,
                    mutable elts: [mutable cell<T>]};

    impl <T: copy> of t<T> for repr<T> {
        fn size() -> uint { ret self.nelts; }
        fn add_front(t: T) {
            let oldlo: uint = self.lo;
            if self.lo == 0u {
                self.lo = vec::len(self.elts) - 1u;
            } else { self.lo -= 1u; }
            if self.lo == self.hi {
                self.elts = grow(self.nelts, oldlo, self.elts);
                self.lo = vec::len(self.elts) - 1u;
                self.hi = self.nelts;
            }
            self.elts[self.lo] = some(t);
            self.nelts += 1u;
        }
        fn add_back(t: T) {
            if self.lo == self.hi && self.nelts != 0u {
                self.elts = grow(self.nelts, self.lo, self.elts);
                self.lo = 0u;
                self.hi = self.nelts;
            }
            self.elts[self.hi] = some(t);
            self.hi = (self.hi + 1u) % vec::len(self.elts);
            self.nelts += 1u;
        }
        /**
         * We actually release (turn to none()) the T we're popping so
         * that we don't keep anyone's refcount up unexpectedly.
         */
        fn pop_front() -> T {
            let t: T = get(self.elts, self.lo);
            self.elts[self.lo] = none;
            self.lo = (self.lo + 1u) % vec::len(self.elts);
            self.nelts -= 1u;
            ret t;
        }
        fn pop_back() -> T {
            if self.hi == 0u {
                self.hi = vec::len(self.elts) - 1u;
            } else { self.hi -= 1u; }
            let t: T = get(self.elts, self.hi);
            self.elts[self.hi] = none;
            self.nelts -= 1u;
            ret t;
        }
        fn peek_front() -> T { ret get(self.elts, self.lo); }
        fn peek_back() -> T { ret get(self.elts, self.hi - 1u); }
        fn get(i: int) -> T {
            let idx = (self.lo + (i as uint)) % vec::len(self.elts);
            ret get(self.elts, idx);
        }
    }

    let repr: repr<T> = {
        mutable nelts: 0u,
        mutable lo: 0u,
        mutable hi: 0u,
        mutable elts: vec::init_elt_mut(none, initial_capacity)
    };
    repr as t::<T>
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;
extern crate mio;

use bluetooth::*;
use std::mem;
use std::error::Error;
use std::os::unix::io::{AsRawFd, FromRawFd};

const AF_BLUETOOTH : i32 = 31;

const BTPROTO_L2CAP : isize = 0;
const BTPROTO_HCI : isize = 1;
const BTPROTO_SCO : isize = 2;
const BTPROTO_RFCOMM : isize = 3;
const BTPROTO_BNEP : isize = 4;
const BTPROTO_CMTP : isize = 5;
const BTPROTO_HIDP : isize = 6;
const BTPROTO_AVDTP : isize = 7;

#[allow(dead_code)]
enum BtProtocolBlueZ {
    L2CAP = BTPROTO_L2CAP,
    HCI = BTPROTO_HCI,
    SCO = BTPROTO_SCO,
    RFCOMM = BTPROTO_RFCOMM,
    BNEP = BTPROTO_BNEP,
    CMTP = BTPROTO_CMTP,
    HIDP = BTPROTO_HIDP,
    AVDTP = BTPROTO_AVDTP
}

#[repr(C)]
#[derive(Copy, Debug, Clone)]
struct sockaddr_rc {
    rc_family : libc::sa_family_t,
    rc_bdaddr : BtAddr,
    rc_channel : u8
}

fn nix_error_to_bterror(error: nix::Error) -> BtError {
    match nix::Error::last() {
        nix::Error::Sys(errno) => BtError::Errno(errno as u32, error.description().to_string()),
        nix::Error::InvalidPath => BtError::Unknown,
    }
}

pub fn new_mio(proto: BtProtocol) -> Result<mio::Io, BtError> {
    match proto {
        BtProtocol::RFCOMM => {
            let fd = unsafe { libc::socket(AF_BLUETOOTH, libc::SOCK_STREAM, BtProtocolBlueZ::RFCOMM as i32) };
            if fd < 0 {
                Err(nix_error_to_bterror(nix::Error::last()))
            } else {
                Ok(mio::Io::from_raw_fd(fd))
            }
        }
    }
}

pub fn connect(io: &mut mio::Io, addr: BtAddr, rc_channel: u32) -> Result<(), BtError> {
    let full_address : sockaddr_rc = sockaddr_rc {
        rc_family : AF_BLUETOOTH as u16,
        rc_bdaddr : addr,
        rc_channel : rc_channel as u8
    };

    if unsafe { libc::connect(io.as_raw_fd(), mem::transmute(&full_address), mem::size_of::<sockaddr_rc>() as u32) } < 0 {
        Err(nix_error_to_bterror(nix::Error::last()))
    } else {
        Ok(())
    }
}
<commit_msg>Implement From<nix::Error> for BtError<commit_after>extern crate libc;
extern crate nix;
extern crate mio;

use bluetooth::*;
use std::mem;
use std::error::Error;
use std::os::unix::io::{AsRawFd, FromRawFd};

const AF_BLUETOOTH : i32 = 31;

const BTPROTO_L2CAP : isize = 0;
const BTPROTO_HCI : isize = 1;
const BTPROTO_SCO : isize = 2;
const BTPROTO_RFCOMM : isize = 3;
const BTPROTO_BNEP : isize = 4;
const BTPROTO_CMTP : isize = 5;
const BTPROTO_HIDP : isize = 6;
const BTPROTO_AVDTP : isize = 7;

#[allow(dead_code)]
enum BtProtocolBlueZ {
    L2CAP = BTPROTO_L2CAP,
    HCI = BTPROTO_HCI,
    SCO = BTPROTO_SCO,
    RFCOMM = BTPROTO_RFCOMM,
    BNEP = BTPROTO_BNEP,
    CMTP = BTPROTO_CMTP,
    HIDP = BTPROTO_HIDP,
    AVDTP = BTPROTO_AVDTP
}

#[repr(C)]
#[derive(Copy, Debug, Clone)]
struct sockaddr_rc {
    rc_family : libc::sa_family_t,
    rc_bdaddr : BtAddr,
    rc_channel : u8
}

impl From<nix::Error> for BtError {
    fn from(e: nix::Error) -> BtError {
        match e {
            nix::Error::Sys(errno) => BtError::Errno(errno as u32, e.description().to_string()),
            nix::Error::InvalidPath => BtError::Unknown,
        }
    }
}

pub fn new_mio(proto: BtProtocol) -> Result<mio::Io, BtError> {
    match proto {
        BtProtocol::RFCOMM => {
            let fd = unsafe { libc::socket(AF_BLUETOOTH, libc::SOCK_STREAM, BtProtocolBlueZ::RFCOMM as i32) };
            if fd < 0 {
                Err(From::from(nix::Error::last()))
            } else {
                Ok(mio::Io::from_raw_fd(fd))
            }
        }
    }
}

pub fn connect(io: &mut mio::Io, addr: BtAddr, rc_channel: u32) -> Result<(), BtError> {
    let full_address : sockaddr_rc = sockaddr_rc {
        rc_family : AF_BLUETOOTH as u16,
        rc_bdaddr : addr,
        rc_channel : rc_channel as u8
    };

    if unsafe { libc::connect(io.as_raw_fd(), mem::transmute(&full_address), mem::size_of::<sockaddr_rc>() as u32) } < 0 {
        Err(From::from(nix::Error::last()))
    } else {
        Ok(())
    }
}
<|endoftext|>


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

//! Checks API calling code.
//!
//! For more information, see [Slack's API
//! documentation](https://api.slack.com/methods).

use std::collections::HashMap;
use hyper;

use super::ApiResult;
use super::make_authed_api_call;

/// Checks API calling code.
///
/// Wraps https://api.slack.com/methods/api.test
pub fn test(client: &hyper::Client, token: &str, args: Option<HashMap<&str, &str>>, error: Option<&str>) -> ApiResult<ApiTestResponse> {
    let mut params = HashMap::new();
    if let Some(error) = error {
        params.insert("error", error);
    }
    if let Some(args) = args {
        params.extend(args);
    }
    make_authed_api_call(client, "api.test", token, params)
}

#[derive(RustcDecodable)]
pub struct ApiTestResponse {
    pub error: Option<String>,
    pub args: Option<HashMap<String, String>>,
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use hyper;
    use super::*;

    mock_slack_responder!(MockErrorResponder, r#"{"ok": false, "err": "some_error"}"#);

    #[test]
    fn general_api_error_response() {
        let client = hyper::Client::with_connector(MockErrorResponder::default());
        let result = test(&client, "TEST_TOKEN", None, Some("some_error"));
        assert!(result.is_err());
    }

    mock_slack_responder!(MockTestOkResponder,
        r#"{
            "ok": true,
            "args": {
                "arg1": "val1",
                "arg2": "val2"
            }
        }"#
    );

    #[test]
    fn test_ok_response() {
        let client = hyper::Client::with_connector(MockTestOkResponder::default());
        let mut args = HashMap::new();
        args.insert("arg1", "val1");
        args.insert("arg2", "val2");
        let result = test(&client, "TEST_TOKEN", Some(args), None);
        if let Err(err) = result {
            panic!(format!("{:?}", err));
        }
        assert_eq!(result.unwrap().args.unwrap().get("arg1").unwrap(), "val1");
    }
}
<commit_msg>Remove unnecessary token parameter on api.test method<commit_after>// Copyright 2015-2016 the slack-rs authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Checks API calling code.
//!
//! For more information, see [Slack's API
//! documentation](https://api.slack.com/methods).

use std::collections::HashMap;
use hyper;

use super::ApiResult;
use super::make_api_call;

/// Checks API calling code.
///
/// Wraps https://api.slack.com/methods/api.test
pub fn test(client: &hyper::Client, args: Option<HashMap<&str, &str>>, error: Option<&str>) -> ApiResult<ApiTestResponse> {
    let mut params = HashMap::new();
    if let Some(error) = error {
        params.insert("error", error);
    }
    if let Some(args) = args {
        params.extend(args);
    }
    make_api_call(client, "api.test", params)
}

#[derive(RustcDecodable)]
pub struct ApiTestResponse {
    pub error: Option<String>,
    pub args: Option<HashMap<String, String>>,
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use hyper;
    use super::*;

    mock_slack_responder!(MockErrorResponder, r#"{"ok": false, "err": "some_error"}"#);

    #[test]
    fn general_api_error_response() {
        let client = hyper::Client::with_connector(MockErrorResponder::default());
        let result = test(&client, None, Some("some_error"));
        assert!(result.is_err());
    }

    mock_slack_responder!(MockTestOkResponder,
        r#"{
            "ok": true,
            "args": {
                "arg1": "val1",
                "arg2": "val2"
            }
        }"#
    );

    #[test]
    fn test_ok_response() {
        let client = hyper::Client::with_connector(MockTestOkResponder::default());
        let mut args = HashMap::new();
        args.insert("arg1", "val1");
        args.insert("arg2", "val2");
        let result = test(&client, Some(args), None);
        if let Err(err) = result {
            panic!(format!("{:?}", err));
        }
        assert_eq!(result.unwrap().args.unwrap().get("arg1").unwrap(), "val1");
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use ast::*;

// TODO: replace Err(msg) with emit_error so semantic checking can continue

pub fn check_program(p: &mut Program) -> Result<(), String> {
    let Program(ref mut fs) = *p;
    let mut ctx = Context::new();
    for f in fs.iter_mut() {
        try!(ctx.check_function(f));
    }
    Ok(())
}

struct Context {
    depth: usize,
    variables: Vec<HashMap<String, Type>>
}

impl Context {
    fn new() -> Context {
        Context {
            depth: 0,
            variables: Vec::new()
        }
    }

    fn push_scope(&mut self) {
        self.variables.push(HashMap::new());
        self.depth = self.variables.len();
    }

    fn pop_scope(&mut self) {
        self.variables.pop();
        self.depth = self.variables.len();
    }

    fn check_function(&mut self, f: &mut Function) -> Result<(), String> {
        self.push_scope();
        for s in f.statements.iter_mut() {
            match self.check_statement(s) {
                Err(msg) => { self.pop_scope(); return Err(msg); },
                Ok(_) => {}
            }
        }
        self.pop_scope();
        Ok(())
    }

    fn check_statement(&mut self, s: &mut Statement) -> Result<(), String> {
        match *s {
            Statement::Block(ref mut v) => {
                self.push_scope();
                for s in v.iter_mut() {
                    match self.check_statement(s) {
                        Err(msg) => { self.pop_scope(); return Err(msg); },
                        Ok(_) => {}
                    }
                }
                self.pop_scope();
                Ok(())
            },

            Statement::Declare(ref mut t, ref ident, ref expr) => {
                let derived = try!(self.derive_type(expr));

                if *t == Type::Unknown {
                    *t = derived.clone();
                }
                if *t == derived {
                    self.variables[self.depth - 1].insert(ident.clone(), t.clone());
                    Ok(())
                } else {
                    Err(format!("value being used to initialise '{}' does not match its declared type (expected: {:?}, actual: {:?})", ident, t, derived))
                }
            },

            Statement::Assign(ref ident, ref expr) => {
                let derived = try!(self.derive_type(expr));
                match self.variables[self.depth - 1].get(ident) {
                    Some(ref t) => if **t != derived {
                        Err(format!("cannot assign rvalue to lvalue of a different type (expected: {:?}, actual: {:?})", t, derived))
                    } else {
                        Ok(())
                    },
                    None => Err(format!("use of undeclared variable '{}'", ident))
                }
            },

            Statement::Return(ref expr) => {
                try!(self.derive_type(expr));
                Ok(())
            }

            Statement::Print(ref expr) => {
                try!(self.derive_type(expr));
                Ok(())
            }
        }
    }

    fn derive_type(&self, expr: &Expression) -> Result<Type, String> {
        match *expr {
            Expression::Int(_) => Ok(Type::Int),
            Expression::Char(_) => Ok(Type::Char),
            Expression::Bool(_) => Ok(Type::Bool),
            Expression::Str(_) => Ok(Type::Str),

            Expression::Identifier(ref ident) => {
                match self.variables[self.depth - 1].get(ident) {
                    Some(ref t) => Ok((*t).clone()),
                    None => Err(format!("use of undeclared variable '{}'", ident))
                }
            },

            Expression::FunctionCall(_) => {
                // Lookup function
                // Get return type
                Err(format!("cannot derive type of function call - unimplemented"))
            }

            Expression::ArrayLiteral(ref v) => {
                let first_type = try!(self.derive_type(&v[0]));
                for e in v.iter() {
                    let et = try!(self.derive_type(e));
                    if first_type != et {
                        return Err(format!("array literal has mixed types"));
                    }
                }
                Ok(Type::Array(Box::new(first_type)))
            }

            Expression::Unary(ref op, ref expr) => {
                let expr_type = try!(self.derive_type(&**expr));
                match *op {
                    UnaryOp::Neg => {
                        match expr_type {
                            Type::Int => Ok(expr_type),
                            _ => Err(format!("invalid type in unary operator '{:?}' (expected: int, actual: {:?})", op, expr_type))
                        }
                    }
                }
            },

            Expression::Binary(ref op, ref lhs, ref rhs) => {
                let t1 = try!(self.derive_type(&**lhs));
                let t2 = try!(self.derive_type(&**rhs));

                if t1 == t2 {
                    match *op {
                        BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => {
                            match t1 {
                                Type::Int => Ok(t1),
                                _ => Err(format!("invalid type on left of operator '{:?}' (expected: int, actual: {:?})", op, t1))
                            }
                        }
                    }
                } else {
                    Err(format!("invalid type on right of operator '{:?}' (expected: {:?}, actual: {:?})", op, t1, t2))
                }
            }
        }
    }
}
<commit_msg>Added more comments to semantic.rs and removed the horrid &** to convert a ref to & as this is now automatic<commit_after>use std::collections::HashMap;
use ast::*;

// TODO: replace Err(msg) with emit_error so semantic checking can continue

pub fn check_program(p: &mut Program) -> Result<(), String> {
    let Program(ref mut fs) = *p;
    let mut ctx = Context::new();
    for f in fs.iter_mut() {
        try!(ctx.check_function(f));
    }
    Ok(())
}

struct Context {
    depth: usize,
    variables: Vec<HashMap<String, Type>>
}

impl Context {
    fn new() -> Context {
        Context {
            depth: 0,
            variables: Vec::new()
        }
    }

    /// Add a new entry to the top of the variable stack
    fn push_scope(&mut self) {
        self.variables.push(HashMap::new());
        self.depth = self.variables.len();
    }

    /// Remove the top of the variable stack
    fn pop_scope(&mut self) {
        self.variables.pop();
        self.depth = self.variables.len();
    }

    /// Given a function, check that it is semantically value
    fn check_function(&mut self, f: &mut Function) -> Result<(), String> {
        self.push_scope();
        for s in f.statements.iter_mut() {
            match self.check_statement(s) {
                Err(msg) => { self.pop_scope(); return Err(msg); },
                Ok(_) => {}
            }
        }
        self.pop_scope();
        Ok(())
    }

    /// Given a statement, check that it is semantically valid
    fn check_statement(&mut self, s: &mut Statement) -> Result<(), String> {
        match *s {
            // Block
            Statement::Block(ref mut v) => {
                self.push_scope();
                for s in v.iter_mut() {
                    match self.check_statement(s) {
                        Err(msg) => { self.pop_scope(); return Err(msg); },
                        Ok(_) => {}
                    }
                }
                self.pop_scope();
                Ok(())
            },

            // Declaration Statement
            Statement::Declare(ref mut t, ref ident, ref expr) => {
                let derived = try!(self.derive_type(expr));

                // If the given type is unknown, then change it to the derived type
                if *t == Type::Unknown {
                    *t = derived.clone();
                }

                // If the LHS matches the RHS, we're okay
                if *t == derived {
                    self.variables[self.depth - 1].insert(ident.clone(), t.clone());
                    Ok(())
                } else {
                    Err(format!("value being used to initialise '{}' does not match its declared type (expected: {:?}, actual: {:?})", ident, t, derived))
                }
            },

            // Assignment Statement
            Statement::Assign(ref ident, ref expr) => {
                let derived = try!(self.derive_type(expr));

                // Look up the variable in the current scope
                // TODO: Check upper scopes and function parameters
                match self.variables[self.depth - 1].get(ident) {
                    // If the variable exists, check that its type matches the RHS
                    Some(ref t) => if **t != derived {
                        Err(format!("cannot assign rvalue to lvalue of a different type (expected: {:?}, actual: {:?})", t, derived))
                    } else {
                        Ok(())
                    },
                    None => Err(format!("use of undeclared variable '{}'", ident))
                }
            },

            // Return Statement
            Statement::Return(ref expr) => {
                try!(self.derive_type(expr));
                Ok(())
            }

            // Print builtin
            Statement::Print(ref expr) => {
                try!(self.derive_type(expr));
                Ok(())
            }
        }
    }

    /// Given an expression, derive it's final type. If there is a problem, then display an error
    /// message and return the 'ERROR' type, so semantic checking can continue.
    fn derive_type(&self, expr: &Expression) -> Result<Type, String> {
        match *expr {
            // Trivial cases
            Expression::Int(_) => Ok(Type::Int),
            Expression::Char(_) => Ok(Type::Char),
            Expression::Bool(_) => Ok(Type::Bool),
            Expression::Str(_) => Ok(Type::Str),

            // A variable identifier
            Expression::Identifier(ref ident) => {
                // If we have an identifier, we need to look it up in the context
                match self.variables[self.depth - 1].get(ident) {
                    Some(ref t) => Ok((*t).clone()),
                    None => Err(format!("use of undeclared variable '{}'", ident))
                }
            },

            // A function call
            Expression::FunctionCall(_) => {
                // Lookup function
                // Get return type
                Err(format!("cannot derive type of function call - unimplemented"))
            }

            // An array literal
            Expression::ArrayLiteral(ref v) => {
                let first_type = try!(self.derive_type(&v[0]));
                for e in v.iter() {
                    let et = try!(self.derive_type(e));
                    if first_type != et {
                        return Err(format!("array literal has mixed types"));
                    }
                }
                Ok(Type::Array(Box::new(first_type)))
            }

            // A unary expression (such as -x or !x)
            Expression::Unary(ref op, ref expr) => {
                let expr_type = try!(self.derive_type(expr));
                match *op {
                    UnaryOp::Neg => {
                        match expr_type {
                            Type::Int => Ok(expr_type),
                            _ => Err(format!("invalid type in unary operator '{:?}' (expected: int, actual: {:?})", op, expr_type))
                        }
                    }
                }
            },

            // A binary expression (such as +, *, /, etc)
            Expression::Binary(ref op, ref lhs, ref rhs) => {
                let t1 = try!(self.derive_type(lhs));
                let t2 = try!(self.derive_type(rhs));

                // If the types of the lhs and the rhs match, then check to ensure the types make
                // sense for the respective operators
                if t1 == t2 {
                    match *op {
                        // Arithmetic operators require an int type
                        BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => {
                            match t1 {
                                Type::Int => Ok(t1),
                                _ => Err(format!("invalid type on left of operator '{:?}' (expected: int, actual: {:?})", op, t1))
                            }
                        }
                    }
                } else {
                    Err(format!("invalid type on right of operator '{:?}' (expected: {:?}, actual: {:?})", op, t1, t2))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use latch::{LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use job::StackJob;
use std::sync::Arc;
use std::error::Error;
use std::fmt;
use thread_pool::{self, Registry, WorkerThread};
use std::mem;
use unwind;

/// Custom error type for the rayon thread pool configuration.
#[derive(Debug,PartialEq)]
pub enum InitError {
    /// Error if number of threads is set to zero.
    NumberOfThreadsZero,

    /// Error if the gloal thread pool is initialized multiple times
    /// and the configuration is not equal for all configurations.
    GlobalPoolAlreadyInitialized,
}

impl fmt::Display for InitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InitError::NumberOfThreadsZero => {
                write!(f,
                       "The number of threads was set to zero but must be greater than zero.")
            }
            InitError::GlobalPoolAlreadyInitialized => {
                write!(f,
                       "The gobal thread pool has already been initialized with a different \
                        configuration. Only one valid configuration is allowed.")
            }
        }
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::NumberOfThreadsZero => "number of threads set to zero",
            InitError::GlobalPoolAlreadyInitialized => {
                "global thread pool has already been initialized"
            }
        }
    }
}

/// Contains the rayon thread pool configuration.
#[derive(Clone, Debug)]
pub struct Configuration {
    /// The number of threads in the rayon thread pool. Must not be zero.
    num_threads: Option<usize>,
}

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration { num_threads: None }
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `set_num_threads` for more information.
    pub fn num_threads(&self) -> Option<usize> {
        self.num_threads
    }

    /// Set the number of threads to be used in the rayon threadpool.
    /// The argument `num_threads` must not be zero. If you do not
    /// call this function, rayon will select a suitable default
    /// (currently, the default is one thread per CPU core).
    pub fn set_num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = Some(num_threads);
        self
    }

    /// Checks whether the configuration is valid.
    fn validate(&self) -> Result<(), InitError> {
        if let Some(value) = self.num_threads {
            if value == 0 {
                return Err(InitError::NumberOfThreadsZero);
            }
        }

        Ok(())
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will simply check that the global thread pool already has the
/// configuration you requested, rather than making changes.
///
/// An `Ok` result indicates that the thread pool is running with the
/// given configuration. Otherwise, a suitable error is returned.
pub fn initialize(config: Configuration) -> Result<(), InitError> {
    try!(config.validate());

    let num_threads = config.num_threads;

    let registry = thread_pool::get_registry_with_config(config);

    if let Some(value) = num_threads {
        if value != registry.num_threads() {
            return Err(InitError::GlobalPoolAlreadyInitialized);
        }
    }

    registry.wait_until_primed();

    Ok(())
}

/// This is a debugging API not really intended for end users. It will
/// dump some performance statistics out using `println`.
pub fn dump_stats() {
    dump_stats!();
}

pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    unsafe {
        let worker_thread = WorkerThread::current();

        // slow path: not yet in the thread pool
        if worker_thread.is_null() {
            return join_inject(oper_a, oper_b);
        }

        log!(Join { worker: (*worker_thread).index() });

        // create virtual wrapper for task b; this all has to be
        // done here so that the stack frame can keep it all live
        // long enough
        let job_b = StackJob::new(oper_b, SpinLatch::new());
        (*worker_thread).push(job_b.as_job_ref());

        // record how many async spawns have occurred on this thread
        // before task A is executed
        let spawn_count = (*worker_thread).current_spawn_count();

        // execute task a; hopefully b gets stolen
        let result_a;
        {
            let guard = unwind::finally(&job_b.latch, |job_b_latch| {
                // If another thread stole our job when we panic, we must halt unwinding
                // until that thread is finished using it.
                if (*WorkerThread::current()).pop().is_none() {
                    job_b_latch.spin();
                }
            });
            result_a = oper_a();
            mem::forget(guard);
        }

        // before we can try to pop b, we have to first pop off any async spawns
        // that have occurred on this thread
        (*worker_thread).pop_spawned_jobs(spawn_count);

        // if b was not stolen, do it ourselves, else wait for the thief to finish
        let result_b;
        if (*worker_thread).pop().is_some() {
            log!(PoppedJob { worker: (*worker_thread).index() });
            result_b = job_b.run_inline(); // not stolen, let's do it!
        } else {
            log!(LostJob { worker: (*worker_thread).index() });
            (*worker_thread).steal_until(&job_b.latch); // stolen, wait for them to finish
            result_b = job_b.into_result();
        }

        // now result_b should be initialized
        (result_a, result_b)
    }
}

#[cold] // cold path
unsafe fn join_inject<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    let job_a = StackJob::new(oper_a, LockLatch::new());
    let job_b = StackJob::new(oper_b, LockLatch::new());

    thread_pool::get_registry().inject(&[job_a.as_job_ref(), job_b.as_job_ref()]);

    job_a.latch.wait();
    job_b.latch.wait();

    (job_a.into_result(), job_b.into_result())
}

pub struct ThreadPool {
    registry: Arc<Registry>,
}

impl ThreadPool {
    /// Constructs a new thread pool with the given configuration. If
    /// the configuration is not valid, returns a suitable `Err`
    /// result.  See `InitError` for more details.
    pub fn new(configuration: Configuration) -> Result<ThreadPool, InitError> {
        try!(configuration.validate());
        Ok(ThreadPool { registry: Registry::new(configuration.num_threads) })
    }

    /// Executes `op` within the threadpool. Any attempts to `join`
    /// which occur there will then operate within that threadpool.
    pub fn install<OP, R>(&self, op: OP) -> R
        where OP: FnOnce() -> R + Send
    {
        unsafe {
            let job_a = StackJob::new(op, LockLatch::new());
            self.registry.inject(&[job_a.as_job_ref()]);
            job_a.latch.wait();
            job_a.into_result()
        }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        self.registry.terminate();
    }
}
<commit_msg>Expose the number of threads in the pool and the index of the current thread.<commit_after>use latch::{LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use job::StackJob;
use std::sync::Arc;
use std::error::Error;
use std::fmt;
use thread_pool::{self, Registry, WorkerThread};
use std::mem;
use unwind;

/// Custom error type for the rayon thread pool configuration.
#[derive(Debug,PartialEq)]
pub enum InitError {
    /// Error if number of threads is set to zero.
    NumberOfThreadsZero,

    /// Error if the gloal thread pool is initialized multiple times
    /// and the configuration is not equal for all configurations.
    GlobalPoolAlreadyInitialized,
}

impl fmt::Display for InitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InitError::NumberOfThreadsZero => {
                write!(f,
                       "The number of threads was set to zero but must be greater than zero.")
            }
            InitError::GlobalPoolAlreadyInitialized => {
                write!(f,
                       "The gobal thread pool has already been initialized with a different \
                        configuration. Only one valid configuration is allowed.")
            }
        }
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::NumberOfThreadsZero => "number of threads set to zero",
            InitError::GlobalPoolAlreadyInitialized => {
                "global thread pool has already been initialized"
            }
        }
    }
}

/// Contains the rayon thread pool configuration.
#[derive(Clone, Debug)]
pub struct Configuration {
    /// The number of threads in the rayon thread pool. Must not be zero.
    num_threads: Option<usize>,
}

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration { num_threads: None }
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `set_num_threads` for more information.
    pub fn num_threads(&self) -> Option<usize> {
        self.num_threads
    }

    /// Set the number of threads to be used in the rayon threadpool.
    /// The argument `num_threads` must not be zero. If you do not
    /// call this function, rayon will select a suitable default
    /// (currently, the default is one thread per CPU core).
    pub fn set_num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = Some(num_threads);
        self
    }

    /// Checks whether the configuration is valid.
    fn validate(&self) -> Result<(), InitError> {
        if let Some(value) = self.num_threads {
            if value == 0 {
                return Err(InitError::NumberOfThreadsZero);
            }
        }

        Ok(())
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will simply check that the global thread pool already has the
/// configuration you requested, rather than making changes.
///
/// An `Ok` result indicates that the thread pool is running with the
/// given configuration. Otherwise, a suitable error is returned.
pub fn initialize(config: Configuration) -> Result<(), InitError> {
    try!(config.validate());

    let num_threads = config.num_threads;

    let registry = thread_pool::get_registry_with_config(config);

    if let Some(value) = num_threads {
        if value != registry.num_threads() {
            return Err(InitError::GlobalPoolAlreadyInitialized);
        }
    }

    registry.wait_until_primed();

    Ok(())
}

/// This is a debugging API not really intended for end users. It will
/// dump some performance statistics out using `println`.
pub fn dump_stats() {
    dump_stats!();
}

pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    unsafe {
        let worker_thread = WorkerThread::current();

        // slow path: not yet in the thread pool
        if worker_thread.is_null() {
            return join_inject(oper_a, oper_b);
        }

        log!(Join { worker: (*worker_thread).index() });

        // create virtual wrapper for task b; this all has to be
        // done here so that the stack frame can keep it all live
        // long enough
        let job_b = StackJob::new(oper_b, SpinLatch::new());
        (*worker_thread).push(job_b.as_job_ref());

        // record how many async spawns have occurred on this thread
        // before task A is executed
        let spawn_count = (*worker_thread).current_spawn_count();

        // execute task a; hopefully b gets stolen
        let result_a;
        {
            let guard = unwind::finally(&job_b.latch, |job_b_latch| {
                // If another thread stole our job when we panic, we must halt unwinding
                // until that thread is finished using it.
                if (*WorkerThread::current()).pop().is_none() {
                    job_b_latch.spin();
                }
            });
            result_a = oper_a();
            mem::forget(guard);
        }

        // before we can try to pop b, we have to first pop off any async spawns
        // that have occurred on this thread
        (*worker_thread).pop_spawned_jobs(spawn_count);

        // if b was not stolen, do it ourselves, else wait for the thief to finish
        let result_b;
        if (*worker_thread).pop().is_some() {
            log!(PoppedJob { worker: (*worker_thread).index() });
            result_b = job_b.run_inline(); // not stolen, let's do it!
        } else {
            log!(LostJob { worker: (*worker_thread).index() });
            (*worker_thread).steal_until(&job_b.latch); // stolen, wait for them to finish
            result_b = job_b.into_result();
        }

        // now result_b should be initialized
        (result_a, result_b)
    }
}

#[cold] // cold path
unsafe fn join_inject<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    let job_a = StackJob::new(oper_a, LockLatch::new());
    let job_b = StackJob::new(oper_b, LockLatch::new());

    thread_pool::get_registry().inject(&[job_a.as_job_ref(), job_b.as_job_ref()]);

    job_a.latch.wait();
    job_b.latch.wait();

    (job_a.into_result(), job_b.into_result())
}

pub struct ThreadPool {
    registry: Arc<Registry>,
}

impl ThreadPool {
    /// Constructs a new thread pool with the given configuration. If
    /// the configuration is not valid, returns a suitable `Err`
    /// result.  See `InitError` for more details.
    pub fn new(configuration: Configuration) -> Result<ThreadPool, InitError> {
        try!(configuration.validate());
        Ok(ThreadPool { registry: Registry::new(configuration.num_threads) })
    }

    /// Executes `op` within the threadpool. Any attempts to `join`
    /// which occur there will then operate within that threadpool.
    pub fn install<OP, R>(&self, op: OP) -> R
        where OP: FnOnce() -> R + Send
    {
        unsafe {
            let job_a = StackJob::new(op, LockLatch::new());
            self.registry.inject(&[job_a.as_job_ref()]);
            job_a.latch.wait();
            job_a.into_result()
        }
    }

    /// Returns the number of threads in the thread pool.
    pub fn num_threads(&self) -> usize {
        self.registry.num_threads()
    }

    /// Returns the index of the current thread in the thread pool. Panics if
    /// the current thread is not in this thread pool.
    pub fn current_thread_index(&self) -> usize {
        unsafe {
            let curr = WorkerThread::current();
            assert!(!curr.is_null());
            (*curr).index()
        }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        self.registry.terminate();
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate hyper;
extern crate params;
extern crate regex;

use self::iron::prelude::*;
use self::iron::status;

use self::hyper::header::{ContentType};
use self::hyper::mime::{Mime, TopLevel, SubLevel};
use self::hyper::status::StatusCode;

use self::params::{Params, Value};

use self::regex::Regex;

use git;
use text_files;
use configuration;

pub fn update_card(request: &mut Request) -> IronResult<Response> {
    if let Ok(params) = request.get_ref::<Params>() {
        if let Some(&Value::String(ref file_name)) = params.find(&["card", "file_name"]) {
            if let Some(&Value::String(ref board)) = params.find(&["card", "board"]) {
                let update = |input: String, output: &mut String| {
                    for line in input.lines() {
                        if line.starts_with("  board:") {
                            output.push_str("  board: ");
                            output.push_str(board);
                        } else {
                            output.push_str(line);
                        }

                        output.push_str("\n");
                    }
                };

                if text_files::update_text_file(& format!(".cardboard/cards/{}", &file_name), update).is_ok() {
                    let repo = git::open(".cardboard");
                    let sha = git::commit_file(
                        &format!("cards/{}", &file_name),
                        &format!("Moved {} to {}", &file_name, &board),
                        &repo
                    );

                    if sha.is_ok() {
                        json_response(r##"{"message": "Card updated"}"##.to_string())
                    } else {
                        json_response_with_status(
                            format!(r##"{{"message": "commit failed: {}"}}"##, sha.err().unwrap()),
                            status::InternalServerError
                        )
                    }
                } else {
                    json_response_with_status(
                        r##"{"message": "Failed to update card"}"##.to_string(),
                        status::BadRequest)
                }
            } else if let Some(&Value::String(ref content)) = params.find(&["card", "content"]) {
                let update = |input: String, output: &mut String| {
                    let meta = configuration::read_meta_yaml(input);

                    output.push_str(&meta);
                    output.push_str("\n\n");
                    output.push_str(content);
                    output.push_str("\n");
                };

                if text_files::update_text_file(& format!(".cardboard/cards/{}", &file_name), update).is_ok() {
                    let repo = git::open(".cardboard");
                    let sha = git::commit_file(
                        &format!("cards/{}", &file_name),
                        &format!("Updated content of {}", &file_name),
                        &repo
                    );

                    if sha.is_ok() {
                        json_response(r##"{"message": "Card updated"}"##.to_string())
                    } else {
                        json_response_with_status(
                            format!(r##"{{"message": "commit failed: {}"}}"##, sha.err().unwrap()),
                            status::InternalServerError
                        )
                    }
                } else {
                    json_response_with_status(
                        r##"{"message": "Failed to update card"}"##.to_string(),
                        status::BadRequest)
                }
            } else {
                json_response_with_status(
                    format!(r##"{{"message": "Cannot update: {:?}"}}"##, params).to_string(),
                    status::BadRequest)
            }
        } else {
            json_response_with_status(
                format!(r##"{{"message": "Cannot update: {:?}"}}"##, params).to_string(),
                status::BadRequest)
        }
    } else {
        json_response_with_status(
            r##"{"message": "Expected JSON request body"}"##.to_string(),
            status::BadRequest)
    }
}

pub fn create_card(request: &mut Request) -> IronResult<Response> {
    if let Ok(params) = request.get_ref::<Params>() {
        if let Some(&Value::String(ref board)) = params.find(&["card", "board"]) {
            if let Some(&Value::String(ref content)) = params.find(&["card", "content"]) {
                let mut output: String = String::new();

                output.push_str("meta:\n");
                output.push_str("  board: ");
                output.push_str(board);
                output.push_str("\n");
                output.push_str("  tags: feature\n"); // tags are not actually used yet
                output.push_str("\n");
                output.push_str(content);
                output.push_str("\n");

                let regex: Regex = Regex::new(r"[^\w]+").unwrap();
                let trim: Regex = Regex::new(r"(^_)|(_$)").unwrap();
                let header: String = content.lines().next().unwrap_or("# New card").to_string();
                let title: String = header[1..].trim().to_lowercase();
                let name: String = trim.replace_all(&regex.replace_all(&title, "_"), "");
                let file_name: &str = &format!("{}.md", name);

                if text_files::create_text_file(& format!(".cardboard/cards/{}", &file_name), output).is_ok() {
                    let repo = git::open(".cardboard");
                    let sha = git::commit_file(
                        &format!("cards/{}", &file_name),
                        &format!("Created {} in {}", &file_name, &board),
                        &repo
                    );

                    if sha.is_ok() {
                        json_response(r##"{"message": "Card created"}"##.to_string())
                    } else {
                        json_response_with_status(
                            format!(r##"{{"message": "commit failed: {}"}}"##, sha.err().unwrap()),
                            status::InternalServerError
                        )
                    }
                } else {
                    json_response_with_status(
                        r##"{"message": "Failed to create card"}"##.to_string(),
                        status::BadRequest)
                }
            } else {
                json_response_with_status(
                    format!(r##"{{"message": "Cannot create card (missing content)"}}"##).to_string(),
                    status::BadRequest)
            }
        } else {
            json_response_with_status(
                format!(r##"{{"message": "Cannot create card (missing board)"}}"##).to_string(),
                status::BadRequest)
        }
    } else {
        json_response_with_status(
            r##"{"message": "Expected JSON request body"}"##.to_string(),
            status::BadRequest)
    }
}

fn json_response(content: String) -> IronResult<Response> {
    json_response_with_status(content, status::Ok)
}

fn json_response_with_status(content: String, status: StatusCode) -> IronResult<Response> {
    let mut response = Response::with((status, content));

    response.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Json, vec![])));

    Ok(response)
}
<commit_msg>refactoring<commit_after>extern crate iron;
extern crate hyper;
extern crate params;
extern crate regex;

use self::iron::prelude::*;
use self::iron::status;

use self::hyper::header::{ContentType};
use self::hyper::mime::{Mime, TopLevel, SubLevel};
use self::hyper::status::StatusCode;

use self::params::{Params, Value};

use self::regex::Regex;

use git;
use text_files;
use configuration;

pub fn update_card(request: &mut Request) -> IronResult<Response> {
    if let Ok(params) = request.get_ref::<Params>() {
        if let Some(&Value::String(ref file_name)) = params.find(&["card", "file_name"]) {
            if let Some(&Value::String(ref board)) = params.find(&["card", "board"]) {
                let update = |input: String, output: &mut String| {
                    for line in input.lines() {
                        if line.starts_with("  board:") {
                            output.push_str("  board: ");
                            output.push_str(board);
                        } else {
                            output.push_str(line);
                        }

                        output.push_str("\n");
                    }
                };

                if text_files::update_text_file(& format!(".cardboard/cards/{}", &file_name), update).is_ok() {
                    let repo = git::open(".cardboard");
                    let sha = git::commit_file(
                        &format!("cards/{}", &file_name),
                        &format!("Moved {} to {}", &file_name, &board),
                        &repo
                    );

                    if sha.is_ok() {
                        json_response(r##"{"message": "Card updated"}"##.to_string())
                    } else {
                        json_response_with_status(
                            format!(r##"{{"message": "commit failed: {}"}}"##, sha.err().unwrap()),
                            status::InternalServerError
                        )
                    }
                } else {
                    json_response_with_status(
                        r##"{"message": "Failed to update card"}"##.to_string(),
                        status::BadRequest)
                }
            } else if let Some(&Value::String(ref content)) = params.find(&["card", "content"]) {
                let update = |input: String, output: &mut String| {
                    let meta = configuration::read_meta_yaml(input);

                    output.push_str(&meta);
                    output.push_str("\n\n");
                    output.push_str(content);
                    output.push_str("\n");
                };

                if text_files::update_text_file(& format!(".cardboard/cards/{}", &file_name), update).is_ok() {
                    let repo = git::open(".cardboard");
                    let sha = git::commit_file(
                        &format!("cards/{}", &file_name),
                        &format!("Updated content of {}", &file_name),
                        &repo
                    );

                    if sha.is_ok() {
                        json_response(r##"{"message": "Card updated"}"##.to_string())
                    } else {
                        json_response_with_status(
                            format!(r##"{{"message": "commit failed: {}"}}"##, sha.err().unwrap()),
                            status::InternalServerError
                        )
                    }
                } else {
                    json_response_with_status(
                        r##"{"message": "Failed to update card"}"##.to_string(),
                        status::BadRequest)
                }
            } else {
                json_response_with_status(
                    format!(r##"{{"message": "Cannot update: {:?}"}}"##, params).to_string(),
                    status::BadRequest)
            }
        } else {
            json_response_with_status(
                format!(r##"{{"message": "Cannot update: {:?}"}}"##, params).to_string(),
                status::BadRequest)
        }
    } else {
        json_response_with_status(
            r##"{"message": "Expected JSON request body"}"##.to_string(),
            status::BadRequest)
    }
}

pub fn create_card(request: &mut Request) -> IronResult<Response> {
    if let Ok(params) = request.get_ref::<Params>() {
        if let Some(&Value::String(ref board)) = params.find(&["card", "board"]) {
            if let Some(&Value::String(ref content)) = params.find(&["card", "content"]) {
                let mut output: String = String::new();

                output.push_str("meta:\n");
                output.push_str("  board: ");
                output.push_str(board);
                output.push_str("\n");
                output.push_str("  tags: feature\n"); // tags are not actually used yet
                output.push_str("\n");
                output.push_str(content);
                output.push_str("\n");

                let regex: Regex = Regex::new(r"[^\w]+").unwrap();
                let trim: Regex = Regex::new(r"(^_)|(_$)").unwrap();
                let header: String = content.lines().next().unwrap_or("# New card").to_string();
                let title: String = header[1..].trim().to_lowercase();
                let name: String = trim.replace_all(&regex.replace_all(&title, "_"), "");
                let file_name: String = format!("{}.md", name);
                let path: String = format!(".cardboard/cards/{}", file_name);

                if text_files::create_text_file(&path, output).is_ok() {
                    let repo = git::open(".cardboard");
                    let sha = git::commit_file(
                        &format!("cards/{}", &file_name),
                        &format!("Created {} in {}", &file_name, &board),
                        &repo
                    );

                    if sha.is_ok() {
                        json_response(r##"{"message": "Card created"}"##.to_string())
                    } else {
                        json_response_with_status(
                            format!(r##"{{"message": "commit failed: {}"}}"##, sha.err().unwrap()),
                            status::InternalServerError
                        )
                    }
                } else {
                    json_response_with_status(
                        r##"{"message": "Failed to create card"}"##.to_string(),
                        status::BadRequest)
                }
            } else {
                json_response_with_status(
                    format!(r##"{{"message": "Cannot create card (missing content)"}}"##).to_string(),
                    status::BadRequest)
            }
        } else {
            json_response_with_status(
                format!(r##"{{"message": "Cannot create card (missing board)"}}"##).to_string(),
                status::BadRequest)
        }
    } else {
        json_response_with_status(
            r##"{"message": "Expected JSON request body"}"##.to_string(),
            status::BadRequest)
    }
}

fn json_response(content: String) -> IronResult<Response> {
    json_response_with_status(content, status::Ok)
}

fn json_response_with_status(content: String, status: StatusCode) -> IronResult<Response> {
    let mut response = Response::with((status, content));

    response.headers.set(ContentType(Mime(TopLevel::Text, SubLevel::Json, vec![])));

    Ok(response)
}
<|endoftext|>