<commit_before>#![feature(macro_rules)]
#![feature(slicing_syntax)]
#![feature(default_type_params)]
#![allow(unused_variables)]
#![allow(dead_code)]

//! # Rules
//! Rules uses regular expressions to do pattern matching using syntax
//! based upon the Perl 6 regex grammar. The Perl 6 grammar has been heavily
//! revised from Perl 5 and should not be equated with it. This may look
//! nothing like any regex you have seen before.
//!
//! # Syntax
//!
//! Currently, this is designed for ASCII and may not behave properly
//! with Unicode.
//!
//! Whitespace is generally ignored to so that a regex can be more readable
//! and less dense.
//!
//! ```rust
//! r"fred"    // Normal way
//! r"f r e d" // Completely equivalent
//! // Will match `apples_oranges` or any other deliminator
//! r"apples . oranges"
//! ```
//!
//! # Set operators
//!
//! These operators can be applied to groups which will be analyzed later:
//!
//! ```plain
//! +       Union                // [123] + [345] = [12345]
//! |       Union                // Same
//! &       Intersection         // [123] & [345] = [3]
//! -       Complement           // [123] - [345] = [1]
//! ^       Symmetric difference // [123] ^ [345] = [1245]
//! ```
//!
//! # Character classes
//!
//! ## Default character classes
//!
//! Character | Matches               | Inverse
//! ----------|-----------------------|--------
//! `.`       | Any character         | N/A
//! `\d`      | Digit                 | `\D`
//! `\h`      | Horizontal whitespace | `\H`
//! `\n`      | Newline               | `\N`
//! `\s`      | Any whitespace        | `\S`
//! `\t`      | Tab                   | `\T`
//! `\w`      | Alphanumeric or `_`   | `\W`
//!
//! ## Custom character classes
//!
//! Characters inside a set of `<[ ]>` form a custom character
//! class:
//!
//! ```plain
//! // Matches `a` or `b` or `c`
//! <[ a b c ]>
//!
//! // `..` expresses a range so this matches
//! // from `a` to `g` or a digit
//! <[ a .. g \d ]>
//!
//! // The `[]` bind the sets together into (non-capturing)
//! // groups so set operators can be used.
//! <[0-9] - [13579]> // Matches an even number
//! <\d - [13579]>    // Same
//! <[0-6] ^ [5-9]>   // Matches a `5` or `6`
//! ```
//!
//! # Comments
//!
//! Comments are allowed inside a regex.
//!
//! ```rust
//! // This matches `myregex`
//! r"my // This is a comment which goes to the end of the line
//! regex"
//! ```

use std::fmt;

#[macro_export]
macro_rules! matches(
    ($expression: expr, $($pattern:pat)|+) => (
        matches!($expression, $($pattern)|+ if true)
    );
    ($expression: expr, $($pattern:pat)|+ if $guard: expr) => (
        match $expression {
            $($pattern)|+ => $guard,
            _ => false
        }
    );
);

enum Mode {
    Match,
    Scan,
}

struct CharSet {
    chars: String,
    // If true include the exact contents. Otherwise, include
    // everything *not* inside `chars`.
    include: bool,
}

impl CharSet {
    fn new(meta: Meta) -> CharSet {
        match meta {
            Meta::Char(c)           => CharSet { chars: String::from_char(1, c), include: true },
            Meta::Digit(test)       => CharSet { chars: "0123456789".to_string(), include: test },
            Meta::Dot               => CharSet { chars: "".to_string(), include: false },
            Meta::Newline(test)     => CharSet { chars: "\n".to_string(), include: test },
            Meta::Tab(test)         => CharSet { chars: "\t".to_string(), include: test },
            Meta::Whitespace(test)  => CharSet { chars: " \t\n".to_string(), include: test },
            Meta::HWhitespace(test) => CharSet { chars: " \t".to_string(), include: test },
            Meta::Word(test)        => CharSet { chars:
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".to_string(),
                include: test },
        }
    }
}

// Types
enum Ty {
    Group(Group),
    Meta(Meta),
    Op(Op),
}

impl fmt::Show for Ty {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Ty::Group(ref ty) => write!(f, "{}", ty),
            Ty::Meta(ref ty)  => write!(f, "{}", ty),
            Ty::Op(ref ty)    => write!(f, "{}", ty),
        }
    }
}

enum Op {
    Ellipsis,                  // ..
    SetDifference,             // -
    SetSymmetricDifference,    // ^
    SetIntersection,           // &
    SetUnion,                  // + or |
}

impl fmt::Show for Op {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Op::Ellipsis => write!(f, ".."),
            Op::SetDifference => write!(f, "-"),
            Op::SetSymmetricDifference => write!(f, "^"),
            Op::SetIntersection => write!(f, "&"),
            Op::SetUnion => write!(f, "+"),
        }
    }
}

enum Group {
//    Capture(Vec<char>),         // ()
    NonCapture(Vec<Ty>), // []
    CharClass(Vec<Ty>),  // <[]>
    Literal(Vec<char>),         // '' or ""
}

impl fmt::Show for Group {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Group::NonCapture(ref vec) => write!(f, "{}", vec),
            Group::CharClass(ref vec)  => write!(f, "<{}>", vec),
            Group::Literal(ref vec)    => write!(f, "{}", vec),
        }
    }
}

// Meta characters are characters which need to be escaped
// to match themselves. For example: `\.` matches a period.
// `.` matches anything.
enum Meta {
    Char(char),             // a b c etc.
    Digit(bool),            // \d
    Dot,                    // .
    Newline(bool),          // \n
    Tab(bool),              // \t
    Whitespace(bool),       // \s
    HWhitespace(bool),      // \h
    Word(bool),             // \w
}

impl fmt::Show for Meta {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Meta::Char(ty) => write!(f, "{}", ty),
            Meta::Digit(ty) => write!(f, "digit({})", ty),
            _ => write!(f, "unimplemented"),
        }
    }
}

impl PartialEq<char> for Meta {
    fn eq(&self, c: &char) -> bool {
        match *self {
            Meta::Char(s) => s == *c,
            Meta::Digit(digit) => {
                let res = matches!(*c, '0' ... '9');
                if digit { res } else { !res }
            },
            Meta::Dot => { true },
            Meta::Tab(tab) => {
                let res = matches!(*c, '\t');
                if tab { res } else { !res }
            },
            Meta::Whitespace(white) => {
                let res = matches!(*c, ' ' | '\t' | '\n');
                if white { res } else { !res }
            },
            Meta::HWhitespace(h_white) => {
                let res = matches!(*c, ' ' | '\t');
                if h_white { res } else { !res }
            },
            Meta::Newline(is) => {
                let res = matches!(*c, '\n');
                if is { res } else { !res }
            },
            Meta::Word(word) => {
                let res = matches!(*c, 'a' ... 'z' |
                                       'A' ... 'Z' |
                                       '0' ... '9' |
                                       '_' );
                if word { res } else { !res }
            },
        }
    }

}

impl Meta {
    // Push characters between first 2 `'` or `"` sets into Literal.
    fn literal(open: char, chars: &mut Iterator<char>) -> Ty {
        let mut vec = vec![];

        while let Some(c) = chars.next() {
            match c {
                _ if c == open => return Ty::Group(Group::Literal(vec)),
                c => vec.push(c),
            }
        }

        // Characters ran out before literal was closed with ' or ".
		panic!(r"The sets of {} are unbalanced.", open);
    }

    fn char_class(chars: &mut Iterator<char>) -> Ty {
        let mut vec = vec![];

        while let Some(c) = chars.next() {
            match c {
                // Ignore whitespace
                ' ' | '\t' | '\n' => continue,

                // Set operators
                '-' => vec.push(Ty::Op(Op::SetDifference)),
                '^' => vec.push(Ty::Op(Op::SetSymmetricDifference)),
                '&' => vec.push(Ty::Op(Op::SetIntersection)),
                '+' => vec.push(Ty::Op(Op::SetUnion)),

                '[' => vec.push(Meta::non_capture(chars)),
                '>' => return Ty::Group(Group::CharClass(vec)),
                _   => panic!("`{}` is not valid inside a character class \
and outside a group.", c),
            }
        }

		panic!(r"Missing a `>` char.");
    }

    fn non_capture(chars: &mut Iterator<char>) -> Ty {
        let mut vec = vec![];

        while let Some(c) = chars.next() {
            match c {
                // Ignore whitespace
                ' ' | '\t' | '\n' => continue,

                'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' | '_'
                            => vec.push(Ty::Meta(Meta::Char(c))),
                '.'  | '\\' => vec.push(Meta::single(c, chars)),
                ']'         => return Ty::Group(Group::NonCapture(vec)),
                c           => panic!("`{}` is an invalid in this position.", c),
            }
        }

		panic!(r"The sets of `]` are unbalanced.");
    }

    // Multiple characters which represent a single symbol.
    fn single(open: char, chars: &mut Iterator<char>) -> Ty {
        match (open, chars.next().expect("Another character is expected.")) {
            // Default character classes
            ('\\', 'd') => Ty::Meta(Meta::Digit(true)),
            ('\\', 'D') => Ty::Meta(Meta::Digit(false)),
            ('\\', 'n') => Ty::Meta(Meta::Newline(true)),
            ('\\', 'N') => Ty::Meta(Meta::Newline(false)),
            ('\\', 't') => Ty::Meta(Meta::Tab(true)),
            ('\\', 'T') => Ty::Meta(Meta::Tab(false)),
            ('\\', 's') => Ty::Meta(Meta::Whitespace(true)),
            ('\\', 'S') => Ty::Meta(Meta::Whitespace(false)),
            ('\\', 'h') => Ty::Meta(Meta::HWhitespace(true)),
            ('\\', 'H') => Ty::Meta(Meta::HWhitespace(false)),
            ('\\', 'w') => Ty::Meta(Meta::Word(true)),
            ('\\', 'W') => Ty::Meta(Meta::Word(false)),
            ('\\', c)   => Ty::Meta(Meta::Char(c)),

            ('.', '.')  => Ty::Op(Op::Ellipsis),
            (a, b)      => panic!(r"`{}{}` is not a valid sequence.", a, b),
        }
    }
    /*fn simplify(class: &mut Meta) -> Meta {
        let mut loc = None;
        for (i, element) in class.iter().enumerate() {
            match element {
                Meta::Union => {
                    loc = Some(i);
                    break;
                },
                _ => {},
            }
        }

    }*/
}

#[deriving(Show)]
pub struct Rule {
    regex: Vec<Ty>,
}

impl Rule {
    pub fn new(s: &str) -> Result<Rule, &'static str> {
        let mut chars = s.chars();
        let mut regex = vec![];

        while let Some(c) = chars.next() {
            match c {
                'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' | '_'
                           => regex.push(Ty::Meta(Meta::Char(c))),
                '.'        => regex.push(Ty::Meta(Meta::Dot)),
                ' ' | '\t' | '\n' => continue,
                '\\'       => regex.push(Meta::single(c, &mut chars)),
                '\'' | '"' => regex.push(Meta::literal(c, &mut chars)),
                '<'        => regex.push(Meta::char_class(&mut chars)),
                '['        => regex.push(Meta::non_capture(&mut chars)),
                _          => continue,
            }
        }
        println!("regex: {}", regex[0]);
        //Meta::simplify(&mut vec[0]);
        Ok(Rule { regex: regex })
    }

    /*pub fn is_match(self, s: &str) -> bool {
        let mut chars = s.chars();
        let mut mode = Mode::Scan;

        loop {
            match mode {
                Mode::Match => {
                    let mut first = true;
                    for regex in self.regex.iter() {
                        // Scan already checked first character so skip iteration.
                        if first {
                            first = false;
                            continue;
                        }

                        if let Some(c) = chars.next() {
                            println!("c: {}, regex: {}", c, regex);
                            // Issue 19035: swapping cmp order breaks code
                            if *regex != c  {
                                mode = Mode::Scan;
                                break;
                            }
                        }
                    }

                    // If finished checking without needing further scanning,
                    // then it found a match.
                    if let Mode::Match = mode { return true; }
                },
                Mode::Scan => {
                    while let Some(c) = chars.next() {
                        // Issue 19035: swapping cmp order breaks code
                        if self.regex[0] == c {
                            mode = Mode::Match;
                            break;
                        }
                    }

                    // If finished scanning string but no match, there isn't a match.
                    if let Mode::Scan = mode { return false; }
                },
            };
        };
    }*/
}

#[cfg(test)]
mod test {
    use super::{CharSet, Meta};

    #[test]
    fn charset_alphanumerics_is_accurate() {

        let CharSet { chars: digits, .. }   = CharSet::new(Meta::Digit(true));
        let CharSet { chars: alphabet, .. } = CharSet::new(Meta::Word(true));

        let mut new_alphabet = vec![];
        let mut new_digits   = vec![];

        for i in range(97, 123u8) { // a-z
            new_alphabet.push(i as char);
        }
        for i in range(65, 91u8) {  // A-Z
            new_alphabet.push(i as char);
        }
        for i in range(48, 58u8) {  // 0-9
            new_alphabet.push(i as char);
            new_digits.push(i as char);
        }

        new_alphabet.push(95u8 as char);   // _

        // Check that typed alphabet is the same as computed
        for (a1, a2) in alphabet.chars().zip(new_alphabet.iter()) {
            assert_eq!(a1, *a2);
        }

        // Check that typed digits are the same as computed
        for (d1, d2) in digits.chars().zip(new_digits.iter()) {
            assert_eq!(d1, *d2);
        }
    }
}

<commit_msg>Hide show implementation<commit_after>#![feature(macro_rules)]
#![feature(slicing_syntax)]
#![feature(default_type_params)]
#![allow(unused_variables)]
#![allow(dead_code)]

//! # Rules
//! Rules uses regular expressions to do pattern matching using syntax
//! based upon the Perl 6 regex grammar. The Perl 6 grammar has been heavily
//! revised from Perl 5 and should not be equated with it. This may look
//! nothing like any regex you have seen before.
//!
//! # Syntax
//!
//! Currently, this is designed for ASCII and may not behave properly
//! with Unicode.
//!
//! Whitespace is generally ignored to so that a regex can be more readable
//! and less dense.
//!
//! ```rust
//! r"fred"    // Normal way
//! r"f r e d" // Completely equivalent
//! // Will match `apples_oranges` or any other deliminator
//! r"apples . oranges"
//! ```
//!
//! # Set operators
//!
//! These operators can be applied to groups which will be analyzed later:
//!
//! ```plain
//! +       Union                // [123] + [345] = [12345]
//! |       Union                // Same
//! &       Intersection         // [123] & [345] = [3]
//! -       Complement           // [123] - [345] = [1]
//! ^       Symmetric difference // [123] ^ [345] = [1245]
//! ```
//!
//! # Character classes
//!
//! ## Default character classes
//!
//! Character | Matches               | Inverse
//! ----------|-----------------------|--------
//! `.`       | Any character         | N/A
//! `\d`      | Digit                 | `\D`
//! `\h`      | Horizontal whitespace | `\H`
//! `\n`      | Newline               | `\N`
//! `\s`      | Any whitespace        | `\S`
//! `\t`      | Tab                   | `\T`
//! `\w`      | Alphanumeric or `_`   | `\W`
//!
//! ## Custom character classes
//!
//! Characters inside a set of `<[ ]>` form a custom character
//! class:
//!
//! ```plain
//! // Matches `a` or `b` or `c`
//! <[ a b c ]>
//!
//! // `..` expresses a range so this matches
//! // from `a` to `g` or a digit
//! <[ a .. g \d ]>
//!
//! // The `[]` bind the sets together into (non-capturing)
//! // groups so set operators can be used.
//! <[0-9] - [13579]> // Matches an even number
//! <\d - [13579]>    // Same
//! <[0-6] ^ [5-9]>   // Matches a `5` or `6`
//! ```
//!
//! # Comments
//!
//! Comments are allowed inside a regex.
//!
//! ```rust
//! // This matches `myregex`
//! r"my // This is a comment which goes to the end of the line
//! regex"
//! ```

use std::fmt;

#[macro_export]
macro_rules! matches(
    ($expression: expr, $($pattern:pat)|+) => (
        matches!($expression, $($pattern)|+ if true)
    );
    ($expression: expr, $($pattern:pat)|+ if $guard: expr) => (
        match $expression {
            $($pattern)|+ => $guard,
            _ => false
        }
    );
);

enum Mode {
    Match,
    Scan,
}

struct CharSet {
    chars: String,
    // If true include the exact contents. Otherwise, include
    // everything *not* inside `chars`.
    include: bool,
}

impl CharSet {
    fn new(meta: Meta) -> CharSet {
        match meta {
            Meta::Char(c)           => CharSet { chars: String::from_char(1, c), include: true },
            Meta::Digit(test)       => CharSet { chars: "0123456789".to_string(), include: test },
            Meta::Dot               => CharSet { chars: "".to_string(), include: false },
            Meta::Newline(test)     => CharSet { chars: "\n".to_string(), include: test },
            Meta::Tab(test)         => CharSet { chars: "\t".to_string(), include: test },
            Meta::Whitespace(test)  => CharSet { chars: " \t\n".to_string(), include: test },
            Meta::HWhitespace(test) => CharSet { chars: " \t".to_string(), include: test },
            Meta::Word(test)        => CharSet { chars:
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".to_string(),
                include: test },
        }
    }
}

// Types
enum Ty {
    Group(Group),
    Meta(Meta),
    Op(Op),
}

enum Op {
    Ellipsis,                  // ..
    SetDifference,             // -
    SetSymmetricDifference,    // ^
    SetIntersection,           // &
    SetUnion,                  // + or |
}

enum Group {
//    Capture(Vec<char>),         // ()
    NonCapture(Vec<Ty>), // []
    CharClass(Vec<Ty>),  // <[]>
    Literal(Vec<char>),         // '' or ""
}

// Meta characters are characters which need to be escaped
// to match themselves. For example: `\.` matches a period.
// `.` matches anything.
enum Meta {
    Char(char),             // a b c etc.
    Digit(bool),            // \d
    Dot,                    // .
    Newline(bool),          // \n
    Tab(bool),              // \t
    Whitespace(bool),       // \s
    HWhitespace(bool),      // \h
    Word(bool),             // \w
}

impl PartialEq<char> for Meta {
    fn eq(&self, c: &char) -> bool {
        match *self {
            Meta::Char(s) => s == *c,
            Meta::Digit(digit) => {
                let res = matches!(*c, '0' ... '9');
                if digit { res } else { !res }
            },
            Meta::Dot => { true },
            Meta::Tab(tab) => {
                let res = matches!(*c, '\t');
                if tab { res } else { !res }
            },
            Meta::Whitespace(white) => {
                let res = matches!(*c, ' ' | '\t' | '\n');
                if white { res } else { !res }
            },
            Meta::HWhitespace(h_white) => {
                let res = matches!(*c, ' ' | '\t');
                if h_white { res } else { !res }
            },
            Meta::Newline(is) => {
                let res = matches!(*c, '\n');
                if is { res } else { !res }
            },
            Meta::Word(word) => {
                let res = matches!(*c, 'a' ... 'z' |
                                       'A' ... 'Z' |
                                       '0' ... '9' |
                                       '_' );
                if word { res } else { !res }
            },
        }
    }

}

impl Meta {
    // Push characters between first 2 `'` or `"` sets into Literal.
    fn literal(open: char, chars: &mut Iterator<char>) -> Ty {
        let mut vec = vec![];

        while let Some(c) = chars.next() {
            match c {
                _ if c == open => return Ty::Group(Group::Literal(vec)),
                c => vec.push(c),
            }
        }

        // Characters ran out before literal was closed with ' or ".
		panic!(r"The sets of {} are unbalanced.", open);
    }

    fn char_class(chars: &mut Iterator<char>) -> Ty {
        let mut vec = vec![];

        while let Some(c) = chars.next() {
            match c {
                // Ignore whitespace
                ' ' | '\t' | '\n' => continue,

                // Set operators
                '-' => vec.push(Ty::Op(Op::SetDifference)),
                '^' => vec.push(Ty::Op(Op::SetSymmetricDifference)),
                '&' => vec.push(Ty::Op(Op::SetIntersection)),
                '+' => vec.push(Ty::Op(Op::SetUnion)),

                '[' => vec.push(Meta::non_capture(chars)),
                '>' => return Ty::Group(Group::CharClass(vec)),
                _   => panic!("`{}` is not valid inside a character class \
and outside a group.", c),
            }
        }

		panic!(r"Missing a `>` char.");
    }

    fn non_capture(chars: &mut Iterator<char>) -> Ty {
        let mut vec = vec![];

        while let Some(c) = chars.next() {
            match c {
                // Ignore whitespace
                ' ' | '\t' | '\n' => continue,

                'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' | '_'
                            => vec.push(Ty::Meta(Meta::Char(c))),
                '.'  | '\\' => vec.push(Meta::single(c, chars)),
                ']'         => return Ty::Group(Group::NonCapture(vec)),
                c           => panic!("`{}` is an invalid in this position.", c),
            }
        }

		panic!(r"The sets of `]` are unbalanced.");
    }

    // Multiple characters which represent a single symbol.
    fn single(open: char, chars: &mut Iterator<char>) -> Ty {
        match (open, chars.next().expect("Another character is expected.")) {
            // Default character classes
            ('\\', 'd') => Ty::Meta(Meta::Digit(true)),
            ('\\', 'D') => Ty::Meta(Meta::Digit(false)),
            ('\\', 'n') => Ty::Meta(Meta::Newline(true)),
            ('\\', 'N') => Ty::Meta(Meta::Newline(false)),
            ('\\', 't') => Ty::Meta(Meta::Tab(true)),
            ('\\', 'T') => Ty::Meta(Meta::Tab(false)),
            ('\\', 's') => Ty::Meta(Meta::Whitespace(true)),
            ('\\', 'S') => Ty::Meta(Meta::Whitespace(false)),
            ('\\', 'h') => Ty::Meta(Meta::HWhitespace(true)),
            ('\\', 'H') => Ty::Meta(Meta::HWhitespace(false)),
            ('\\', 'w') => Ty::Meta(Meta::Word(true)),
            ('\\', 'W') => Ty::Meta(Meta::Word(false)),
            ('\\', c)   => Ty::Meta(Meta::Char(c)),

            ('.', '.')  => Ty::Op(Op::Ellipsis),
            (a, b)      => panic!(r"`{}{}` is not a valid sequence.", a, b),
        }
    }
    /*fn simplify(class: &mut Meta) -> Meta {
        let mut loc = None;
        for (i, element) in class.iter().enumerate() {
            match element {
                Meta::Union => {
                    loc = Some(i);
                    break;
                },
                _ => {},
            }
        }

    }*/
}

#[deriving(Show)]
pub struct Rule {
    regex: Vec<Ty>,
}

impl Rule {
    pub fn new(s: &str) -> Result<Rule, &'static str> {
        let mut chars = s.chars();
        let mut regex = vec![];

        while let Some(c) = chars.next() {
            match c {
                'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' | '_'
                           => regex.push(Ty::Meta(Meta::Char(c))),
                '.'        => regex.push(Ty::Meta(Meta::Dot)),
                ' ' | '\t' | '\n' => continue,
                '\\'       => regex.push(Meta::single(c, &mut chars)),
                '\'' | '"' => regex.push(Meta::literal(c, &mut chars)),
                '<'        => regex.push(Meta::char_class(&mut chars)),
                '['        => regex.push(Meta::non_capture(&mut chars)),
                _          => continue,
            }
        }
        println!("regex: {}", regex[0]);
        //Meta::simplify(&mut vec[0]);
        Ok(Rule { regex: regex })
    }

    /*pub fn is_match(self, s: &str) -> bool {
        let mut chars = s.chars();
        let mut mode = Mode::Scan;

        loop {
            match mode {
                Mode::Match => {
                    let mut first = true;
                    for regex in self.regex.iter() {
                        // Scan already checked first character so skip iteration.
                        if first {
                            first = false;
                            continue;
                        }

                        if let Some(c) = chars.next() {
                            println!("c: {}, regex: {}", c, regex);
                            // Issue 19035: swapping cmp order breaks code
                            if *regex != c  {
                                mode = Mode::Scan;
                                break;
                            }
                        }
                    }

                    // If finished checking without needing further scanning,
                    // then it found a match.
                    if let Mode::Match = mode { return true; }
                },
                Mode::Scan => {
                    while let Some(c) = chars.next() {
                        // Issue 19035: swapping cmp order breaks code
                        if self.regex[0] == c {
                            mode = Mode::Match;
                            break;
                        }
                    }

                    // If finished scanning string but no match, there isn't a match.
                    if let Mode::Scan = mode { return false; }
                },
            };
        };
    }*/
}

#[cfg(test)]
mod test {
    use super::{CharSet, Meta};

    #[test]
    fn charset_alphanumerics_is_accurate() {

        let CharSet { chars: digits, .. }   = CharSet::new(Meta::Digit(true));
        let CharSet { chars: alphabet, .. } = CharSet::new(Meta::Word(true));

        let mut new_alphabet = vec![];
        let mut new_digits   = vec![];

        for i in range(97, 123u8) { // a-z
            new_alphabet.push(i as char);
        }
        for i in range(65, 91u8) {  // A-Z
            new_alphabet.push(i as char);
        }
        for i in range(48, 58u8) {  // 0-9
            new_alphabet.push(i as char);
            new_digits.push(i as char);
        }

        new_alphabet.push(95u8 as char);   // _

        // Check that typed alphabet is the same as computed
        for (a1, a2) in alphabet.chars().zip(new_alphabet.iter()) {
            assert_eq!(a1, *a2);
        }

        // Check that typed digits are the same as computed
        for (d1, d2) in digits.chars().zip(new_digits.iter()) {
            assert_eq!(d1, *d2);
        }
    }
}

<|endoftext|>


<commit_before>#![license = "MIT"]
#![feature(plugin_registrar, managed_boxes)]
#![deny(warnings)]

//! Stainless is a lightweight, unopinionated testing framework for Rust.

extern crate syntax;
extern crate rustc;

use self::describe::describe;
use rustc::plugin;

mod describe;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut plugin::Registry) {
    reg.register_macro("describe", describe);
}

<commit_msg>(cleanup) Removed unnecessary managed_boxes feature.<commit_after>#![license = "MIT"]
#![feature(plugin_registrar)]
#![deny(warnings)]

//! Stainless is a lightweight, unopinionated testing framework for Rust.

extern crate syntax;
extern crate rustc;

use self::describe::describe;
use rustc::plugin;

mod describe;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut plugin::Registry) {
    reg.register_macro("describe", describe);
}

<|endoftext|>


<commit_before>//! A probability-theory toolbox.
//!
//! ## Example
//!
//! ```
//! use probability::prelude::*;
//!
//! let mut source = random::default();
//! let uniform = Uniform::new(0.0, 1.0);
//! let samples = Independent(&uniform, &mut source).take(10).collect::<Vec<_>>();
//! ```

#[cfg(test)]
extern crate assert;

extern crate random;
extern crate special;

macro_rules! should(
    ($requirement:expr) => ({
        debug_assert!($requirement);
    });
    ($requirement:expr, $code:expr) => ({
        debug_assert!($code, stringify!($requirement))
    });
);

pub mod distribution;
pub mod prelude;
pub mod sampler;
<commit_msg>Make a cosmetic adjustment to should!<commit_after>//! A probability-theory toolbox.
//!
//! ## Example
//!
//! ```
//! use probability::prelude::*;
//!
//! let mut source = random::default();
//! let uniform = Uniform::new(0.0, 1.0);
//! let samples = Independent(&uniform, &mut source).take(10).collect::<Vec<_>>();
//! ```

#[cfg(test)]
extern crate assert;

extern crate random;
extern crate special;

macro_rules! should(
    ($requirement:expr) => (debug_assert!($requirement));
    ($requirement:expr, $code:expr) => (debug_assert!($code, stringify!($requirement)));
);

pub mod distribution;
pub mod prelude;
pub mod sampler;
<|endoftext|>


<commit_before>// Many of my decisions were based off the following document
// https://web.archive.org/web/20140727185616/http://algs4.cs.princeton.edu/33balanced/

// TODO:
// Collection trait
// convert this to Key/Value K/V

use std::cmp::Ord;
use std::option::{None, Option, Some};

/// Four
enum Four<V: Ord> {
    InternalFour(V, V, V, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>),
    LeafFour(V, V, V),
}

impl <V: Ord> Four<V> {
    fn to_two(self) -> Two<V> {
        match self {
            LeafFour(v1, v2, v3) =>
                Two(v2,
                    box LeafTwoNode(LeafTwo(v1)),
                    box LeafTwoNode(LeafTwo(v3))),
            InternalFour(v1, v2, v3, n1, n2, n3, n4) =>
                Two(v2,
                    box TwoNode(Two(v1, n1, n2)),
                    box TwoNode(Two(v3, n3, n4))),
        }
    }
}

/// InsertResult
enum InsertResult<V: Ord> {
    Fit(Node<V>),
    Split(Four<V>),
}

/// Direction
enum Direction {
    Left,
    Middle,
    Right,
    Leaf,
}

/// Two
pub struct Two<V: Ord>(pub V, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Two<V> {
    fn to_node(self) -> Node<V> { TwoNode(self) }

    fn to_three(self, other_value: V, other_node: Box<Node<V>>) -> Three<V> {
        let Two(self_value, self_left, self_middle) = self;
        if self_value > other_value {
            Three(other_value, self_value, other_node, self_left, self_middle)
        } else {
            Three(self_value, other_value, self_left, self_middle, other_node)
        }
    }
}

/// Three
pub struct Three<V: Ord>(pub V, pub V, pub Box<Node<V>>, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Three<V> {
    fn to_node(self) -> Node<V> { ThreeNode(self) }

    fn to_four(self, other_value: V, other_node: Box<Node<V>>) -> Four<V> {
        let Three(self_value1, self_value2, self_left, self_middle, self_right) = self;
        if other_value < self_value1 {
            InternalFour(other_value, self_value1, self_value2, other_node, self_left, self_middle, self_right)
        } else {
            InternalFour(self_value1, self_value2, other_value, self_left, self_middle, self_right, other_node)
        }
    }
}

/// LeafTwo
pub struct LeafTwo<V: Ord>(pub V);

impl <V: Ord> LeafTwo<V> {
    fn to_three(self, other_value: V) -> LeafThree<V> {
        let LeafTwo(self_value) = self;
        if self_value > other_value {
            LeafThree(other_value, self_value)
        } else {
            LeafThree(self_value, other_value)
        }
    }
}

/// LeafThree
pub struct LeafThree<V: Ord>(pub V, pub V);

impl <V: Ord> LeafThree<V> {
    fn to_node(self) -> Node<V> { LeafThreeNode(self) }

    fn to_four(self, value: V) -> Four<V> {
        let LeafThree(value1, value2) = self;
        if value > value2      { LeafFour(value1, value2, value) }
        else if value < value1 { LeafFour(value, value1, value2) }
        else                   { LeafFour(value1, value, value2) }
    }
}

/// Node
pub enum Node<V: Ord> {
    LeafTwoNode(LeafTwo<V>),
    LeafThreeNode(LeafThree<V>),
    TwoNode(Two<V>),
    ThreeNode(Three<V>),
}

impl <V: Ord> Node<V> {
    fn next_direction(&self, to_insert: &V) -> Direction {
        match self {
            &TwoNode(Two(ref value, _, _)) =>
                if to_insert < value { Left }
                else                 { Middle },
            &ThreeNode(Three(ref value1, ref value2, _, _, _)) =>
                if      to_insert < value1 { Left }
                else if to_insert > value2 { Right }
                else                       { Middle },
            _ => Leaf,
        }
    }

    fn contains_node(&self, to_check: &V) -> bool {
        match self {
            &TwoNode(Two(ref v, _, _)) |
                &LeafTwoNode(LeafTwo(ref v)) if to_check == v => true,

            &ThreeNode(Three(ref v1, ref v2, _, _, _)) |
                &LeafThreeNode(LeafThree(ref v1, ref v2)) if to_check == v1 || to_check == v2 => true,

            _ => false
        }
    }

    fn insert(self, to_insert: V) -> InsertResult<V> {
        // If value is already in this node, we're done (prevent duplicates)
        if self.contains_node(&to_insert) { return Fit(self); }

        let next_direction = self.next_direction(&to_insert);

        match self {
            // Insert if leaf TwoNode
            LeafTwoNode(leaf_two) => {
                let three_node = leaf_two.to_three(to_insert);
                Fit(three_node.to_node())
            },

            // Split if leaf ThreeNode
            LeafThreeNode(leaf_three) => {
                let four_node = leaf_three.to_four(to_insert);
                Split(four_node)
            },

            // Recurse down if internal Node and handle results
            TwoNode(Two(value, box left, box middle)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node) = match next_direction {
                    Left => (left, middle),
                    Middle => (middle, left),
                    _ => panic!(""),
                };

                // Recurse, save the result of the insert
                let insert_result = next_node.insert(to_insert);

                // Handle the result of the insert
                let new_node = match insert_result {
                    Fit(returned_node) =>
                        match next_direction {
                            Left =>   Two(value, box returned_node, box other_node),
                            Middle => Two(value, box other_node, box returned_node),
                            _ => panic!(""),
                        }.to_node(),
                    Split(four_node) => four_node.to_two().to_three(value, box other_node).to_node(),
                };

                Fit(new_node)
            },

            // Recurse down if internal Node and handle results
            ThreeNode(Three(value1, value2, left, middle, right)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node1, other_node2) = match next_direction {
                    Left => (left, middle, right),
                    Middle => (middle, left, right),
                    Right => (right, left, middle),
                    _ => panic!(""),
                };

                let insert_result = next_node.insert(to_insert);

                match insert_result {
                    Fit(returned_node) => {
                        let three = match next_direction {
                            Left =>   Three(value1, value2, box returned_node, other_node1, other_node2),
                            Middle => Three(value1, value2, other_node1, box returned_node, other_node2),
                            Right =>  Three(value1, value2, other_node1, other_node2, box returned_node),
                            _ => panic!(""),
                        };
                        Fit(three.to_node())
                    },
                    Split(four_node) => {
                        let two = four_node.to_two();
                        let new_node = match next_direction {
                            Left =>   two.to_three(value1, other_node1).to_four(value2, other_node2),
                            Middle => two.to_three(value1, other_node1).to_four(value2, other_node2),
                            Right =>  two.to_three(value2, other_node2).to_four(value1, other_node1),
                            _ => panic!(""),
                        };
                        Split(new_node)
                    }
                }
            }
        }
    }
}

/// TTTree
pub struct TTTree<V: Ord> {
    pub root: Option<Node<V>>,
}

impl <V: Ord> TTTree<V> {
    pub fn new() -> TTTree<V> {
        TTTree { root: None }
    }

    pub fn insert(&mut self, value: V) -> () {
        let root: Option<Node<V>> = self.root.take();
        let new_root: Node<V> = match root {
            None => LeafTwoNode(LeafTwo(value)),
            Some(root) => {
                let result = root.insert(value);
                match result {
                    Fit(node) => node,
                    Split(four_node) => four_node.to_two().to_node(),
                }
            }
        };
        self.root = Some(new_root);
    }
}
<commit_msg>Rename to->as for wrapping method<commit_after>// Many of my decisions were based off the following document
// https://web.archive.org/web/20140727185616/http://algs4.cs.princeton.edu/33balanced/

// TODO:
// Collection trait
// convert this to Key/Value K/V

use std::cmp::Ord;
use std::option::{None, Option, Some};

/// Four
enum Four<V: Ord> {
    InternalFour(V, V, V, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>),
    LeafFour(V, V, V),
}

impl <V: Ord> Four<V> {
    fn to_two(self) -> Two<V> {
        match self {
            LeafFour(v1, v2, v3) =>
                Two(v2,
                    box LeafTwoNode(LeafTwo(v1)),
                    box LeafTwoNode(LeafTwo(v3))),
            InternalFour(v1, v2, v3, n1, n2, n3, n4) =>
                Two(v2,
                    box TwoNode(Two(v1, n1, n2)),
                    box TwoNode(Two(v3, n3, n4))),
        }
    }
}

/// InsertResult
enum InsertResult<V: Ord> {
    Fit(Node<V>),
    Split(Four<V>),
}

/// Direction
enum Direction {
    Left,
    Middle,
    Right,
    Leaf,
}

/// Two
pub struct Two<V: Ord>(pub V, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Two<V> {
    fn as_node(self) -> Node<V> { TwoNode(self) }

    fn to_three(self, other_value: V, other_node: Box<Node<V>>) -> Three<V> {
        let Two(self_value, self_left, self_middle) = self;
        if self_value > other_value {
            Three(other_value, self_value, other_node, self_left, self_middle)
        } else {
            Three(self_value, other_value, self_left, self_middle, other_node)
        }
    }
}

/// Three
pub struct Three<V: Ord>(pub V, pub V, pub Box<Node<V>>, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Three<V> {
    fn as_node(self) -> Node<V> { ThreeNode(self) }

    fn to_four(self, other_value: V, other_node: Box<Node<V>>) -> Four<V> {
        let Three(self_value1, self_value2, self_left, self_middle, self_right) = self;
        if other_value < self_value1 {
            InternalFour(other_value, self_value1, self_value2, other_node, self_left, self_middle, self_right)
        } else {
            InternalFour(self_value1, self_value2, other_value, self_left, self_middle, self_right, other_node)
        }
    }
}

/// LeafTwo
pub struct LeafTwo<V: Ord>(pub V);

impl <V: Ord> LeafTwo<V> {
    fn to_three(self, other_value: V) -> LeafThree<V> {
        let LeafTwo(self_value) = self;
        if self_value > other_value {
            LeafThree(other_value, self_value)
        } else {
            LeafThree(self_value, other_value)
        }
    }
}

/// LeafThree
pub struct LeafThree<V: Ord>(pub V, pub V);

impl <V: Ord> LeafThree<V> {
    fn as_node(self) -> Node<V> { LeafThreeNode(self) }

    fn to_four(self, value: V) -> Four<V> {
        let LeafThree(value1, value2) = self;
        if value > value2      { LeafFour(value1, value2, value) }
        else if value < value1 { LeafFour(value, value1, value2) }
        else                   { LeafFour(value1, value, value2) }
    }
}

/// Node
pub enum Node<V: Ord> {
    LeafTwoNode(LeafTwo<V>),
    LeafThreeNode(LeafThree<V>),
    TwoNode(Two<V>),
    ThreeNode(Three<V>),
}

impl <V: Ord> Node<V> {
    fn next_direction(&self, to_insert: &V) -> Direction {
        match self {
            &TwoNode(Two(ref value, _, _)) =>
                if to_insert < value { Left }
                else                 { Middle },
            &ThreeNode(Three(ref value1, ref value2, _, _, _)) =>
                if      to_insert < value1 { Left }
                else if to_insert > value2 { Right }
                else                       { Middle },
            _ => Leaf,
        }
    }

    fn contains_node(&self, to_check: &V) -> bool {
        match self {
            &TwoNode(Two(ref v, _, _)) |
                &LeafTwoNode(LeafTwo(ref v)) if to_check == v => true,

            &ThreeNode(Three(ref v1, ref v2, _, _, _)) |
                &LeafThreeNode(LeafThree(ref v1, ref v2)) if to_check == v1 || to_check == v2 => true,

            _ => false
        }
    }

    fn insert(self, to_insert: V) -> InsertResult<V> {
        // If value is already in this node, we're done (prevent duplicates)
        if self.contains_node(&to_insert) { return Fit(self); }

        let next_direction = self.next_direction(&to_insert);

        match self {
            // Insert if leaf TwoNode
            LeafTwoNode(leaf_two) => {
                let three_node = leaf_two.to_three(to_insert);
                Fit(three_node.as_node())
            },

            // Split if leaf ThreeNode
            LeafThreeNode(leaf_three) => {
                let four_node = leaf_three.to_four(to_insert);
                Split(four_node)
            },

            // Recurse down if internal Node and handle results
            TwoNode(Two(value, box left, box middle)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node) = match next_direction {
                    Left => (left, middle),
                    Middle => (middle, left),
                    _ => panic!(""),
                };

                // Recurse, save the result of the insert
                let insert_result = next_node.insert(to_insert);

                // Handle the result of the insert
                let new_node = match insert_result {
                    Fit(returned_node) =>
                        match next_direction {
                            Left =>   Two(value, box returned_node, box other_node),
                            Middle => Two(value, box other_node, box returned_node),
                            _ => panic!(""),
                        }.as_node(),
                    Split(four_node) => four_node.to_two().to_three(value, box other_node).as_node(),
                };

                Fit(new_node)
            },

            // Recurse down if internal Node and handle results
            ThreeNode(Three(value1, value2, left, middle, right)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node1, other_node2) = match next_direction {
                    Left => (left, middle, right),
                    Middle => (middle, left, right),
                    Right => (right, left, middle),
                    _ => panic!(""),
                };

                let insert_result = next_node.insert(to_insert);

                match insert_result {
                    Fit(returned_node) => {
                        let three = match next_direction {
                            Left =>   Three(value1, value2, box returned_node, other_node1, other_node2),
                            Middle => Three(value1, value2, other_node1, box returned_node, other_node2),
                            Right =>  Three(value1, value2, other_node1, other_node2, box returned_node),
                            _ => panic!(""),
                        };
                        Fit(three.as_node())
                    },
                    Split(four_node) => {
                        let two = four_node.to_two();
                        let new_node = match next_direction {
                            Left =>   two.to_three(value1, other_node1).to_four(value2, other_node2),
                            Middle => two.to_three(value1, other_node1).to_four(value2, other_node2),
                            Right =>  two.to_three(value2, other_node2).to_four(value1, other_node1),
                            _ => panic!(""),
                        };
                        Split(new_node)
                    }
                }
            }
        }
    }
}

/// TTTree
pub struct TTTree<V: Ord> {
    pub root: Option<Node<V>>,
}

impl <V: Ord> TTTree<V> {
    pub fn new() -> TTTree<V> {
        TTTree { root: None }
    }

    pub fn insert(&mut self, value: V) -> () {
        let root: Option<Node<V>> = self.root.take();
        let new_root: Node<V> = match root {
            None => LeafTwoNode(LeafTwo(value)),
            Some(root) => {
                let result = root.insert(value);
                match result {
                    Fit(node) => node,
                    Split(four_node) => four_node.to_two().as_node(),
                }
            }
        };
        self.root = Some(new_root);
    }
}
<|endoftext|>


<commit_before>#![feature(core,
           std_misc,
           collections)]

//! **petgraph** is a graph data structure library.
//!
//! The most interesting type is [**Graph**](./graph/struct.Graph.html) which is
//! a directed or undirected graph with owned mutably accessible arbitrary node and edge weights.
//! It is based on rustc's graph implementation.

use std::marker;
use std::cmp::Ordering;
use std::hash::{self, Hash};
use std::fmt;
use std::ops::{Deref};

pub use scored::MinScored;
pub use graphmap::GraphMap;
pub use graph::Graph;

pub use self::EdgeDirection::{Outgoing, Incoming};
pub use visit::{
    Bfs,
    Dfs,
};

mod scored;
pub mod algo;
pub mod graphmap;
pub mod graph;
pub mod parse;
pub mod visit;

pub mod unionfind;
mod isomorphism;
mod dijkstra;
mod traits_graph;

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EdgeDirection {
    /// A **Outgoing** edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An **Incoming** edge is an inbound edge *to* the current node.
    Incoming = 1
}

/// Marker type for a directed graph.
#[derive(Copy, Clone, Debug)]
pub struct Directed;

/// Marker type for an undirected graph.
#[derive(Copy, Clone, Debug)]
pub struct Undirected;

/// A graph's edge type determines whether is has directed edges or not.
pub trait EdgeType : marker::MarkerTrait {
    fn is_directed() -> bool;
}

impl EdgeType for Directed {
    #[inline]
    fn is_directed() -> bool { true }
}

impl EdgeType for Undirected {
    #[inline]
    fn is_directed() -> bool { false }
}

/// A reference that is hashed and compared by its pointer value.
pub struct Ptr<'b, T: 'b>(pub &'b T);

impl<'b, T> Copy for Ptr<'b, T> {}
impl<'b, T> Clone for Ptr<'b, T>
{
    fn clone(&self) -> Self { *self }
}

fn ptreq<T>(a: &T, b: &T) -> bool {
    a as *const _ == b as *const _
}

impl<'b, T> PartialEq for Ptr<'b, T>
{
    /// Ptr compares by pointer equality, i.e if they point to the same value
    fn eq(&self, other: &Ptr<'b, T>) -> bool {
        ptreq(self.0, other.0)
    }
}

impl<'b, T> PartialOrd for Ptr<'b, T>
{
    fn partial_cmp(&self, other: &Ptr<'b, T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'b, T> Ord for Ptr<'b, T>
{
    /// Ptr is ordered by pointer value, i.e. an arbitrary but stable and total order.
    fn cmp(&self, other: &Ptr<'b, T>) -> Ordering {
        let a = self.0 as *const _;
        let b = other.0 as *const _;
        a.cmp(&b)
    }
}

impl<'b, T> Deref for Ptr<'b, T> {
    type Target = T;
    fn deref<'a>(&'a self) -> &'a T {
        self.0
    }
}

impl<'b, T> Eq for Ptr<'b, T> {}

impl<'b, T> Hash for Ptr<'b, T>
{
    fn hash<H: hash::Hasher>(&self, st: &mut H)
    {
        let ptr = (self.0) as *const _;
        ptr.hash(st)
    }
}

impl<'b, T: fmt::Debug> fmt::Debug for Ptr<'b, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}
<commit_msg>Remove unused feature flag<commit_after>#![feature(core,
           collections)]

//! **petgraph** is a graph data structure library.
//!
//! The most interesting type is [**Graph**](./graph/struct.Graph.html) which is
//! a directed or undirected graph with owned mutably accessible arbitrary node and edge weights.
//! It is based on rustc's graph implementation.

use std::marker;
use std::cmp::Ordering;
use std::hash::{self, Hash};
use std::fmt;
use std::ops::{Deref};

pub use scored::MinScored;
pub use graphmap::GraphMap;
pub use graph::Graph;

pub use self::EdgeDirection::{Outgoing, Incoming};
pub use visit::{
    Bfs,
    Dfs,
};

mod scored;
pub mod algo;
pub mod graphmap;
pub mod graph;
pub mod parse;
pub mod visit;

pub mod unionfind;
mod isomorphism;
mod dijkstra;
mod traits_graph;

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EdgeDirection {
    /// A **Outgoing** edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An **Incoming** edge is an inbound edge *to* the current node.
    Incoming = 1
}

/// Marker type for a directed graph.
#[derive(Copy, Clone, Debug)]
pub struct Directed;

/// Marker type for an undirected graph.
#[derive(Copy, Clone, Debug)]
pub struct Undirected;

/// A graph's edge type determines whether is has directed edges or not.
pub trait EdgeType : marker::MarkerTrait {
    fn is_directed() -> bool;
}

impl EdgeType for Directed {
    #[inline]
    fn is_directed() -> bool { true }
}

impl EdgeType for Undirected {
    #[inline]
    fn is_directed() -> bool { false }
}

/// A reference that is hashed and compared by its pointer value.
pub struct Ptr<'b, T: 'b>(pub &'b T);

impl<'b, T> Copy for Ptr<'b, T> {}
impl<'b, T> Clone for Ptr<'b, T>
{
    fn clone(&self) -> Self { *self }
}

fn ptreq<T>(a: &T, b: &T) -> bool {
    a as *const _ == b as *const _
}

impl<'b, T> PartialEq for Ptr<'b, T>
{
    /// Ptr compares by pointer equality, i.e if they point to the same value
    fn eq(&self, other: &Ptr<'b, T>) -> bool {
        ptreq(self.0, other.0)
    }
}

impl<'b, T> PartialOrd for Ptr<'b, T>
{
    fn partial_cmp(&self, other: &Ptr<'b, T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'b, T> Ord for Ptr<'b, T>
{
    /// Ptr is ordered by pointer value, i.e. an arbitrary but stable and total order.
    fn cmp(&self, other: &Ptr<'b, T>) -> Ordering {
        let a = self.0 as *const _;
        let b = other.0 as *const _;
        a.cmp(&b)
    }
}

impl<'b, T> Deref for Ptr<'b, T> {
    type Target = T;
    fn deref<'a>(&'a self) -> &'a T {
        self.0
    }
}

impl<'b, T> Eq for Ptr<'b, T> {}

impl<'b, T> Hash for Ptr<'b, T>
{
    fn hash<H: hash::Hasher>(&self, st: &mut H)
    {
        let ptr = (self.0) as *const _;
        ptr.hash(st)
    }
}

impl<'b, T: fmt::Debug> fmt::Debug for Ptr<'b, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

extern crate habitat_core as hab_core;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate log;
extern crate openssl;

pub mod error;

use std::sync::Arc;
use std::path::Path;

use hab_core::env::http_proxy_unless_domain_exempted;
use hyper::client::Client;
use hyper::client::pool::{Config, Pool};
use hyper::http::h1::Http11Protocol;
use hyper::net::{HttpsConnector, Openssl};
use hyper::Url;
use openssl::ssl::{SslContext, SslMethod, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION};

pub use error::{Error, Result};

/// Builds a new hyper HTTP client with appropriate SSL configuration and HTTP/HTTPS proxy support.
///
/// ## Linux Platforms
///
/// We need a set of root certificates when connected to SSL/TLS web endpoints and this usually
/// boild down to using an all-in-one certificate file (such as a `cacert.pem` file) or a directory
/// of files which are certificates. The strategy to location or use a reasonable set of
/// certificates is as follows:
///
/// 1. If the `SSL_CERT_FILE` environment variable is set, then use its value for the certificates.
///    Interally this is triggering default OpenSSL behavior for this environment variable.
/// 2. If the `SSL_CERT_DIR` environment variable is set, then use its value for the directory
///    containing certificates. Like the `SSL_CERT_FILE` case above, this triggers default OpenSSL
///    behavior for this environment variable.
/// 3. If the `core/cacerts` Habitat package is installed locally, then use the latest release's
///    `cacert.pem` file.
/// 4. If none of the conditions above are met, then a `cacert.pem` will be written in an SSL cache
///    directory (by default `/hab/cache/ssl` for a root user and `$HOME/.hab/cache/ssl` for a
///    non-root user) and this will be used. The contents of this file will be inlined in this
///    crate at build time as a fallback insurance policy, meaning that if the a program using this
///    code is operating in a minimal environment which may not contain system certificates, it can
///    still operate. Once a `core/cacerts` Habitat package is present, the logic would fall back
///    to preferring the package version to the cached/inline file version.
///
/// ## Mac Platforms
///
/// The Mac platoform uses a Security Framework to store and find root certificates and the hyper
/// library will default to using this on the Mac. Therefore the behavior on the Mac remains
/// unchanged and will use the system's certificates.
///
pub fn new_hyper_client(for_domain: Option<&Url>, fs_root_path: Option<&Path>) -> Result<Client> {
    let for_domain = match for_domain {
        Some(url) => url.host_str().unwrap_or(""),
        None => "",
    };
    match try!(http_proxy_unless_domain_exempted(for_domain)) {
        Some((proxy_host, proxy_port)) => {
            debug!("Using proxy {}:{}...", &proxy_host, &proxy_port);
            Ok(Client::with_http_proxy(proxy_host, proxy_port))
        }
        None => {
            let ctx = try!(ssl_ctx(fs_root_path));
            let connector = HttpsConnector::new(Openssl { context: Arc::new(ctx) });
            let pool = Pool::with_connector(Config::default(), connector);
            Ok(Client::with_protocol(Http11Protocol::with_connector(pool)))
        }
    }
}

fn ssl_ctx(fs_root_path: Option<&Path>) -> Result<SslContext> {
    // The spirit of this implementation is directly from Hyper's default OpensslClient function:
    // https://github.com/hyperium/hyper/blob/v0.9.5/src/net.rs#L653-L661
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ssl::set_ca(&mut ctx, fs_root_path));
    ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
    try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH"));
    Ok(ctx)
}

#[cfg(target_os = "linux")]
mod ssl {
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::Path;
    use std::str::FromStr;

    use hab_core::env;
    use hab_core::fs::cache_ssl_path;
    use hab_core::package::{PackageIdent, PackageInstall};
    use openssl::ssl::SslContext;

    use error::Result;

    const CACERTS_PKG_IDENT: &'static str = "core/cacerts";
    const CACERT_PEM: &'static str = include_str!(concat!(env!("OUT_DIR"), "/cacert.pem"));

    pub fn set_ca(ctx: &mut SslContext, fs_root_path: Option<&Path>) -> Result<()> {
        let cacerts_ident = try!(PackageIdent::from_str(CACERTS_PKG_IDENT));

        if let Ok(_) = env::var("SSL_CERT_FILE") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(_) = env::var("SSL_CERT_DIR") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(pkg_install) = PackageInstall::load(&cacerts_ident, fs_root_path) {
            let pkg_certs = pkg_install.installed_path().join("ssl/cert.pem");
            debug!("Setting CA file for SSL context to: {}",
                   pkg_certs.display());
            try!(ctx.set_CA_file(pkg_certs));
        } else {
            let cached_certs = cache_ssl_path(fs_root_path).join("cert.pem");
            if !cached_certs.exists() {
                try!(fs::create_dir_all(cache_ssl_path(None)));
                debug!("Creating cached cacert.pem at: {}", cached_certs.display());
                let mut file = try!(File::create(&cached_certs));
                try!(file.write_all(CACERT_PEM.as_bytes()));
            }
            debug!("Setting CA file for SSL context to: {}",
                   cached_certs.display());
            try!(ctx.set_CA_file(cached_certs));
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
mod ssl {
    use std::path::Path;

    use openssl::ssl::SslContext;

    use error::Result;

    pub fn set_ca(ctx: &mut SslContext, _fs_root_path: Option<&Path>) -> Result<()> {
        try!(ctx.set_default_verify_paths());
        Ok(())
    }
}
<commit_msg>[http-client] Drop support for http_proxy pending upstream support.<commit_after>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

extern crate habitat_core as hab_core;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate log;
extern crate openssl;

pub mod error;

use std::sync::Arc;
use std::path::Path;

use hyper::client::Client;
use hyper::client::pool::{Config, Pool};
use hyper::http::h1::Http11Protocol;
use hyper::net::{HttpsConnector, Openssl};
use hyper::Url;
use openssl::ssl::{SslContext, SslMethod, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION};

pub use error::{Error, Result};

/// Builds a new hyper HTTP client with appropriate SSL configuration and HTTP/HTTPS proxy support.
///
/// ## Linux Platforms
///
/// We need a set of root certificates when connected to SSL/TLS web endpoints and this usually
/// boild down to using an all-in-one certificate file (such as a `cacert.pem` file) or a directory
/// of files which are certificates. The strategy to location or use a reasonable set of
/// certificates is as follows:
///
/// 1. If the `SSL_CERT_FILE` environment variable is set, then use its value for the certificates.
///    Interally this is triggering default OpenSSL behavior for this environment variable.
/// 2. If the `SSL_CERT_DIR` environment variable is set, then use its value for the directory
///    containing certificates. Like the `SSL_CERT_FILE` case above, this triggers default OpenSSL
///    behavior for this environment variable.
/// 3. If the `core/cacerts` Habitat package is installed locally, then use the latest release's
///    `cacert.pem` file.
/// 4. If none of the conditions above are met, then a `cacert.pem` will be written in an SSL cache
///    directory (by default `/hab/cache/ssl` for a root user and `$HOME/.hab/cache/ssl` for a
///    non-root user) and this will be used. The contents of this file will be inlined in this
///    crate at build time as a fallback insurance policy, meaning that if the a program using this
///    code is operating in a minimal environment which may not contain system certificates, it can
///    still operate. Once a `core/cacerts` Habitat package is present, the logic would fall back
///    to preferring the package version to the cached/inline file version.
///
/// ## Mac Platforms
///
/// The Mac platoform uses a Security Framework to store and find root certificates and the hyper
/// library will default to using this on the Mac. Therefore the behavior on the Mac remains
/// unchanged and will use the system's certificates.
///
pub fn new_hyper_client(_for_domain: Option<&Url>, fs_root_path: Option<&Path>) -> Result<Client> {
    let ctx = try!(ssl_ctx(fs_root_path));
    let connector = HttpsConnector::new(Openssl { context: Arc::new(ctx) });
    let pool = Pool::with_connector(Config::default(), connector);
    Ok(Client::with_protocol(Http11Protocol::with_connector(pool)))
}

fn ssl_ctx(fs_root_path: Option<&Path>) -> Result<SslContext> {
    // The spirit of this implementation is directly from Hyper's default OpensslClient function:
    // https://github.com/hyperium/hyper/blob/v0.9.5/src/net.rs#L653-L661
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ssl::set_ca(&mut ctx, fs_root_path));
    ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
    try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH"));
    Ok(ctx)
}

#[cfg(target_os = "linux")]
mod ssl {
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::Path;
    use std::str::FromStr;

    use hab_core::env;
    use hab_core::fs::cache_ssl_path;
    use hab_core::package::{PackageIdent, PackageInstall};
    use openssl::ssl::SslContext;

    use error::Result;

    const CACERTS_PKG_IDENT: &'static str = "core/cacerts";
    const CACERT_PEM: &'static str = include_str!(concat!(env!("OUT_DIR"), "/cacert.pem"));

    pub fn set_ca(ctx: &mut SslContext, fs_root_path: Option<&Path>) -> Result<()> {
        let cacerts_ident = try!(PackageIdent::from_str(CACERTS_PKG_IDENT));

        if let Ok(_) = env::var("SSL_CERT_FILE") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(_) = env::var("SSL_CERT_DIR") {
            try!(ctx.set_default_verify_paths());
        } else if let Ok(pkg_install) = PackageInstall::load(&cacerts_ident, fs_root_path) {
            let pkg_certs = pkg_install.installed_path().join("ssl/cert.pem");
            debug!("Setting CA file for SSL context to: {}",
                   pkg_certs.display());
            try!(ctx.set_CA_file(pkg_certs));
        } else {
            let cached_certs = cache_ssl_path(fs_root_path).join("cert.pem");
            if !cached_certs.exists() {
                try!(fs::create_dir_all(cache_ssl_path(None)));
                debug!("Creating cached cacert.pem at: {}", cached_certs.display());
                let mut file = try!(File::create(&cached_certs));
                try!(file.write_all(CACERT_PEM.as_bytes()));
            }
            debug!("Setting CA file for SSL context to: {}",
                   cached_certs.display());
            try!(ctx.set_CA_file(cached_certs));
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
mod ssl {
    use std::path::Path;

    use openssl::ssl::SslContext;

    use error::Result;

    pub fn set_ca(ctx: &mut SslContext, _fs_root_path: Option<&Path>) -> Result<()> {
        try!(ctx.set_default_verify_paths());
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Custom memory allocators and utilities for using them.
//!
//! # Examples
//! ```rust
//! #![feature(placement_in_syntax)]
//!
//! use std::io;
//! use allocators::{Allocator, Scoped, BlockOwner, Proxy};
//!
//! #[derive(Debug)]
//! struct Bomb(u8);
//!
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new scoped allocator with 4 kilobytes of memory.
//! let alloc = Scoped::new(4 * 1024).unwrap();
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     // allocate makes the value on the stack first.
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).unwrap())}
//!     // there's also in-place allocation!
//!     let bomb_101 = in inner.make_place().unwrap() { Bomb(101) };
//!     // watch the bombs go off!
//! });
//!
//!
//! // You can make allocators backed by other allocators.
//! {
//!     let secondary_alloc = Scoped::new_from(&alloc, 1024).unwrap();
//!     let mut val = secondary_alloc.allocate(0i32).unwrap();
//!     *val = 1;
//! }
//!
//! // Let's wrap our allocator in a proxy to log what it's doing.
//! let proxied = Proxy::new(alloc, io::stdout());
//! let logged_allocation = proxied.allocate([0u8; 32]).unwrap();
//! ```

#![feature(
    alloc,
    coerce_unsized,
    core_intrinsics,
    heap_api,
    placement_new_protocol,
    placement_in_syntax,
    raw,
    unsize,
)]

use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::fmt;
use std::marker::{PhantomData, Unsize};
use std::mem;
use std::ops::Place as StdPlace;
use std::ops::{CoerceUnsized, Deref, DerefMut, InPlace, Placer};

use alloc::heap;

extern crate alloc;

pub mod composable;
pub mod scoped;

pub use composable::*;
pub use scoped::Scoped;

/// A custom memory allocator.
pub unsafe trait Allocator {
    /// Attempts to allocate the value supplied to it.
    ///
    /// # Examples
    /// ```rust
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     allocator.allocate([0; 1000]).ok().unwrap()
    /// }
    /// ```
    #[inline(always)]
    fn allocate<T>(&self, val: T) -> Result<Allocated<T, Self>, (AllocatorError, T)>
        where Self: Sized
    {
        match self.make_place() {
            Ok(place) => {
                Ok(in place { val })
            }
            Err(err) => {
                Err((err, val))
            }
        }
    }

    /// Attempts to create a place to allocate into.
    /// For the general purpose, calling `allocate` on the allocator is enough.
    /// However, when you know the value you are allocating is too large
    /// to be constructed on the stack, you should use in-place allocation.
    ///
    /// # Examples
    /// ```rust
    /// #![feature(placement_in_syntax)]
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     // if 1000 bytes were enough to smash the stack, this would still work.
    ///     in allocator.make_place().unwrap() { [0; 1000] }
    /// }
    /// ```
    fn make_place<T>(&self) -> Result<Place<T, Self>, AllocatorError>
        where Self: Sized
    {
        let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
        match unsafe { self.allocate_raw(size, align) } {
            Ok(blk) => {
                Ok(Place {
                    allocator: self,
                    block: blk,
                    _marker: PhantomData
                })
            }
            Err(e) => Err(e),
        }
    }

    /// Attempt to allocate a block of memory.
    ///
    /// Returns either a pointer to the block of memory allocated
    /// or an Error. If `size` is equal to 0, the pointer returned must
    /// be equal to `heap::EMPTY`
    ///
    /// # Safety
    /// Never use the pointer outside of the lifetime of the allocator.
    /// It must be deallocated with the same allocator as it was allocated with.
    /// It is undefined behavior to provide a non power-of-two align.
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError>;

    /// Deallocate the memory referred to by this pointer.
    ///
    /// # Safety
    /// This block must have been allocated by this allocator.
    unsafe fn deallocate_raw(&self, blk: Block);
}

/// An allocator that knows which blocks have been issued by it.
pub trait BlockOwner: Allocator {
    /// Whether this allocator owns this allocated value.
    fn owns<'a, T, A: Allocator>(&self, val: &Allocated<'a, T, A>) -> bool {
        self.owns_block(&val.block)
    }

    /// Whether this allocator owns the block passed to it.
    fn owns_block(&self, blk: &Block) -> bool;

    /// Joins this allocator with a fallback allocator.
    // TODO: Maybe not the right place for this?
    // Right now I've been more focused on shaking out the
    // specifics of allocation than crafting a fluent API.
    fn with_fallback<O: BlockOwner>(self, other: O) -> Fallback<Self, O>
    where Self: Sized {
        Fallback::new(self, other)
    }
}

/// A block of memory created by an allocator.
// TODO: should blocks be tied to lifetimes? seems good for safety!
pub struct Block<'a> {
    ptr: *mut u8,
    size: usize,
    align: usize,
    _marker: PhantomData<&'a [u8]>
}

impl<'a> Block<'a> {
    pub fn new(ptr: *mut u8, size: usize, align: usize) -> Self {
        Block {
            ptr: ptr,
            size: size,
            align: align,
            _marker: PhantomData,
        }
    }

    pub fn ptr(&self) -> *mut u8 { self.ptr }
    pub fn size(&self) -> usize { self.size }
    pub fn align(&self) -> usize { self.align }
}

impl<'a> Clone for Block<'a> {
    fn clone(&self) -> Block<'a> {
        Block {
            ptr: self.ptr(),
            size: self.size(),
            align: self.align(),
            _marker: self._marker
        }
    }
}

/// Errors that can occur while creating an allocator
/// or allocating from it.
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
    /// The allocator failed to allocate the amount of memory requested of it.
    OutOfMemory,
    /// An allocator-specific error message.
    AllocatorSpecific(String),
}

impl fmt::Display for AllocatorError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.description())
    }
}

impl Error for AllocatorError {
    fn description(&self) -> &str {
        use AllocatorError::*;

        match *self {
            OutOfMemory => {
                "Allocator out of memory."
            }
            AllocatorSpecific(ref reason) => {
                reason
            }
        }
    }
}

/// Allocator stub that just forwards to heap allocation.
/// It is recommended to use the `HEAP` constant instead
/// of creating a new instance of this, to benefit from
/// the static lifetime that it provides.
#[derive(Debug)]
pub struct HeapAllocator;

// A constant for allocators to use the heap as a root.
// Values allocated with this are effectively `Box`es.
pub const HEAP: &'static HeapAllocator = &HeapAllocator;

unsafe impl Allocator for HeapAllocator {
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError> {
        let ptr = if size != 0 {
            heap::allocate(size, align)
        } else {
            heap::EMPTY as *mut u8
        };

        if ptr.is_null() {
            Err(AllocatorError::OutOfMemory)
        } else {
            Ok(Block::new(ptr, size, align))
        }
    }

    unsafe fn deallocate_raw(&self, blk: Block) {
        heap::deallocate(blk.ptr(), blk.size(), blk.align())
    }
}

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a + ?Sized, A: 'a + Allocator> {
    item: *mut T,
    allocator: &'a A,
    block: Block<'a>,
}

impl<'a, T: ?Sized, A: Allocator> Deref for Allocated<'a, T, A> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { mem::transmute(self.item) }
    }
}

impl<'a, T: ?Sized, A: Allocator> DerefMut for Allocated<'a, T, A> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { mem::transmute(self.item) }
    }
}

// Allocated can store trait objects!
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Allocated<'a, U, A>> for Allocated<'a, T, A> {}

impl<'a, A: Allocator> Allocated<'a, Any, A> {
    /// Attempts to downcast this `Allocated` to a concrete type.
    pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T, A>, Allocated<'a, Any, A>> {
        use std::raw::TraitObject;
        if self.is::<T>() {
            let obj: TraitObject = unsafe { mem::transmute(self.item as *mut Any) };
            let new_allocated = Allocated {
                item: obj.data as *mut T,
                allocator: self.allocator,
                block: self.block.clone(),
            };
            mem::forget(self);
            Ok(new_allocated)
        } else {
            Err(self)
        }
    }
}

impl<'a, T: ?Sized, A: Allocator> Borrow<T> for Allocated<'a, T, A> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<'a, T: ?Sized, A: Allocator> BorrowMut<T> for Allocated<'a, T, A> {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}

impl<'a, T: ?Sized, A: Allocator> Drop for Allocated<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        use std::intrinsics::drop_in_place;
        unsafe {
            drop_in_place(self.item);
;
            self.allocator.deallocate_raw(self.block.clone());
        }

    }
}

/// A place for allocating into.
/// This is only used for in-place allocation,
/// e.g. `let val = in (alloc.make_place().unwrap())`
pub struct Place<'a, T: 'a, A: 'a + Allocator> {
    allocator: &'a A,
    block: Block<'a>,
    _marker: PhantomData<T>,
}

impl<'a, T: 'a, A: 'a + Allocator> Placer<T> for Place<'a, T, A> {
    type Place = Self;
    fn make_place(self) -> Self { self }
}

impl<'a, T: 'a, A: 'a + Allocator> InPlace<T> for Place<'a, T, A> {
    type Owner = Allocated<'a, T, A>;
    unsafe fn finalize(self) -> Self::Owner {
        let allocated = Allocated {
            item: self.block.ptr() as *mut T,
            allocator: self.allocator,
            block: self.block.clone()
        };

        mem::forget(self);
        allocated
    }
}

impl<'a, T: 'a, A: 'a + Allocator> StdPlace<T> for Place<'a, T, A> {
    fn pointer(&mut self) -> *mut T {
        self.block.ptr() as *mut T
    }
}

impl<'a, T: 'a, A: 'a + Allocator> Drop for Place<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        // almost identical to Allocated::Drop, but we don't drop
        // the value in place. This is because if the finalize
        // method was never called, that means the expression
        // to create the value failed, and the memory at the
        // pointer is still uninitialized.
        unsafe {
            self.allocator.deallocate_raw(self.block.clone());
        }

    }
}

// aligns a pointer forward to the next value aligned with `align`.
#[inline(always)]
fn align_forward(ptr: *mut u8, align: usize) -> *mut u8 {
    ((ptr as usize + align - 1) & !(align - 1)) as *mut u8
}

#[cfg(test)]
mod tests {

    use std::any::Any;

    use super::*;

    #[test]
    fn heap_lifetime() {
        let my_int;
        {
            my_int = HEAP.allocate(0i32).unwrap();
        }

        assert_eq!(*my_int, 0);
    }
    #[test]
    fn heap_in_place() {
        let big = in HEAP.make_place().unwrap() { [0u8; 8_000_000] };
        assert_eq!(big.len(), 8_000_000);
    }

    #[test]
    fn unsizing() {
        #[derive(Debug)]
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) {
                println!("Boom")
            }
        }

        let my_foo: Allocated<Any, _> = HEAP.allocate(Bomb).unwrap();
        let _: Allocated<Bomb, _> = my_foo.downcast().ok().unwrap();
    }
}<commit_msg>Removed unnecessary transmutes. Clarified the remaining.<commit_after>//! Custom memory allocators and utilities for using them.
//!
//! # Examples
//! ```rust
//! #![feature(placement_in_syntax)]
//!
//! use std::io;
//! use allocators::{Allocator, Scoped, BlockOwner, Proxy};
//!
//! #[derive(Debug)]
//! struct Bomb(u8);
//!
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new scoped allocator with 4 kilobytes of memory.
//! let alloc = Scoped::new(4 * 1024).unwrap();
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     // allocate makes the value on the stack first.
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).unwrap())}
//!     // there's also in-place allocation!
//!     let bomb_101 = in inner.make_place().unwrap() { Bomb(101) };
//!     // watch the bombs go off!
//! });
//!
//!
//! // You can make allocators backed by other allocators.
//! {
//!     let secondary_alloc = Scoped::new_from(&alloc, 1024).unwrap();
//!     let mut val = secondary_alloc.allocate(0i32).unwrap();
//!     *val = 1;
//! }
//!
//! // Let's wrap our allocator in a proxy to log what it's doing.
//! let proxied = Proxy::new(alloc, io::stdout());
//! let logged_allocation = proxied.allocate([0u8; 32]).unwrap();
//! ```

#![feature(
    alloc,
    coerce_unsized,
    core_intrinsics,
    heap_api,
    placement_new_protocol,
    placement_in_syntax,
    raw,
    unsize,
)]

use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::fmt;
use std::marker::{PhantomData, Unsize};
use std::mem;
use std::ops::Place as StdPlace;
use std::ops::{CoerceUnsized, Deref, DerefMut, InPlace, Placer};

use alloc::heap;

extern crate alloc;

pub mod composable;
pub mod scoped;

pub use composable::*;
pub use scoped::Scoped;

/// A custom memory allocator.
pub unsafe trait Allocator {
    /// Attempts to allocate the value supplied to it.
    ///
    /// # Examples
    /// ```rust
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     allocator.allocate([0; 1000]).ok().unwrap()
    /// }
    /// ```
    #[inline(always)]
    fn allocate<T>(&self, val: T) -> Result<Allocated<T, Self>, (AllocatorError, T)>
        where Self: Sized
    {
        match self.make_place() {
            Ok(place) => {
                Ok(in place { val })
            }
            Err(err) => {
                Err((err, val))
            }
        }
    }

    /// Attempts to create a place to allocate into.
    /// For the general purpose, calling `allocate` on the allocator is enough.
    /// However, when you know the value you are allocating is too large
    /// to be constructed on the stack, you should use in-place allocation.
    ///
    /// # Examples
    /// ```rust
    /// #![feature(placement_in_syntax)]
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     // if 1000 bytes were enough to smash the stack, this would still work.
    ///     in allocator.make_place().unwrap() { [0; 1000] }
    /// }
    /// ```
    fn make_place<T>(&self) -> Result<Place<T, Self>, AllocatorError>
        where Self: Sized
    {
        let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
        match unsafe { self.allocate_raw(size, align) } {
            Ok(blk) => {
                Ok(Place {
                    allocator: self,
                    block: blk,
                    _marker: PhantomData
                })
            }
            Err(e) => Err(e),
        }
    }

    /// Attempt to allocate a block of memory.
    ///
    /// Returns either a pointer to the block of memory allocated
    /// or an Error. If `size` is equal to 0, the pointer returned must
    /// be equal to `heap::EMPTY`
    ///
    /// # Safety
    /// Never use the pointer outside of the lifetime of the allocator.
    /// It must be deallocated with the same allocator as it was allocated with.
    /// It is undefined behavior to provide a non power-of-two align.
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError>;

    /// Deallocate the memory referred to by this pointer.
    ///
    /// # Safety
    /// This block must have been allocated by this allocator.
    unsafe fn deallocate_raw(&self, blk: Block);
}

/// An allocator that knows which blocks have been issued by it.
pub trait BlockOwner: Allocator {
    /// Whether this allocator owns this allocated value.
    fn owns<'a, T, A: Allocator>(&self, val: &Allocated<'a, T, A>) -> bool {
        self.owns_block(&val.block)
    }

    /// Whether this allocator owns the block passed to it.
    fn owns_block(&self, blk: &Block) -> bool;

    /// Joins this allocator with a fallback allocator.
    // TODO: Maybe not the right place for this?
    // Right now I've been more focused on shaking out the
    // specifics of allocation than crafting a fluent API.
    fn with_fallback<O: BlockOwner>(self, other: O) -> Fallback<Self, O>
    where Self: Sized {
        Fallback::new(self, other)
    }
}

/// A block of memory created by an allocator.
// TODO: should blocks be tied to lifetimes? seems good for safety!
pub struct Block<'a> {
    ptr: *mut u8,
    size: usize,
    align: usize,
    _marker: PhantomData<&'a [u8]>
}

impl<'a> Block<'a> {
    pub fn new(ptr: *mut u8, size: usize, align: usize) -> Self {
        Block {
            ptr: ptr,
            size: size,
            align: align,
            _marker: PhantomData,
        }
    }

    pub fn ptr(&self) -> *mut u8 { self.ptr }
    pub fn size(&self) -> usize { self.size }
    pub fn align(&self) -> usize { self.align }
}

impl<'a> Clone for Block<'a> {
    fn clone(&self) -> Block<'a> {
        Block {
            ptr: self.ptr(),
            size: self.size(),
            align: self.align(),
            _marker: self._marker
        }
    }
}

/// Errors that can occur while creating an allocator
/// or allocating from it.
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
    /// The allocator failed to allocate the amount of memory requested of it.
    OutOfMemory,
    /// An allocator-specific error message.
    AllocatorSpecific(String),
}

impl fmt::Display for AllocatorError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.description())
    }
}

impl Error for AllocatorError {
    fn description(&self) -> &str {
        use AllocatorError::*;

        match *self {
            OutOfMemory => {
                "Allocator out of memory."
            }
            AllocatorSpecific(ref reason) => {
                reason
            }
        }
    }
}

/// Allocator stub that just forwards to heap allocation.
/// It is recommended to use the `HEAP` constant instead
/// of creating a new instance of this, to benefit from
/// the static lifetime that it provides.
#[derive(Debug)]
pub struct HeapAllocator;

// A constant for allocators to use the heap as a root.
// Values allocated with this are effectively `Box`es.
pub const HEAP: &'static HeapAllocator = &HeapAllocator;

unsafe impl Allocator for HeapAllocator {
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError> {
        let ptr = if size != 0 {
            heap::allocate(size, align)
        } else {
            heap::EMPTY as *mut u8
        };

        if ptr.is_null() {
            Err(AllocatorError::OutOfMemory)
        } else {
            Ok(Block::new(ptr, size, align))
        }
    }

    unsafe fn deallocate_raw(&self, blk: Block) {
        heap::deallocate(blk.ptr(), blk.size(), blk.align())
    }
}

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a + ?Sized, A: 'a + Allocator> {
    item: *mut T,
    allocator: &'a A,
    block: Block<'a>,
}

impl<'a, T: ?Sized, A: Allocator> Deref for Allocated<'a, T, A> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.item }
    }
}

impl<'a, T: ?Sized, A: Allocator> DerefMut for Allocated<'a, T, A> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.item }
    }
}

// Allocated can store trait objects!
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Allocated<'a, U, A>> for Allocated<'a, T, A> {}

impl<'a, A: Allocator> Allocated<'a, Any, A> {
    /// Attempts to downcast this `Allocated` to a concrete type.
    pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T, A>, Allocated<'a, Any, A>> {
        use std::raw::TraitObject;
        if self.is::<T>() {
            let obj: TraitObject = unsafe { mem::transmute::<*mut Any, TraitObject>(self.item) };
            let new_allocated = Allocated {
                item: obj.data as *mut T,
                allocator: self.allocator,
                block: self.block.clone(),
            };
            mem::forget(self);
            Ok(new_allocated)
        } else {
            Err(self)
        }
    }
}

impl<'a, T: ?Sized, A: Allocator> Borrow<T> for Allocated<'a, T, A> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<'a, T: ?Sized, A: Allocator> BorrowMut<T> for Allocated<'a, T, A> {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}

impl<'a, T: ?Sized, A: Allocator> Drop for Allocated<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        use std::intrinsics::drop_in_place;
        unsafe {
            drop_in_place(self.item);
;
            self.allocator.deallocate_raw(self.block.clone());
        }

    }
}

/// A place for allocating into.
/// This is only used for in-place allocation,
/// e.g. `let val = in (alloc.make_place().unwrap()) { EXPR }`
pub struct Place<'a, T: 'a, A: 'a + Allocator> {
    allocator: &'a A,
    block: Block<'a>,
    _marker: PhantomData<T>,
}

impl<'a, T: 'a, A: 'a + Allocator> Placer<T> for Place<'a, T, A> {
    type Place = Self;
    fn make_place(self) -> Self { self }
}

impl<'a, T: 'a, A: 'a + Allocator> InPlace<T> for Place<'a, T, A> {
    type Owner = Allocated<'a, T, A>;
    unsafe fn finalize(self) -> Self::Owner {
        let allocated = Allocated {
            item: self.block.ptr() as *mut T,
            allocator: self.allocator,
            block: self.block.clone()
        };

        mem::forget(self);
        allocated
    }
}

impl<'a, T: 'a, A: 'a + Allocator> StdPlace<T> for Place<'a, T, A> {
    fn pointer(&mut self) -> *mut T {
        self.block.ptr() as *mut T
    }
}

impl<'a, T: 'a, A: 'a + Allocator> Drop for Place<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        // almost identical to Allocated::Drop, but we don't drop
        // the value in place. This is because if the finalize
        // method was never called, that means the expression
        // to create the value failed, and the memory at the
        // pointer is still uninitialized.
        unsafe {
            self.allocator.deallocate_raw(self.block.clone());
        }

    }
}

// aligns a pointer forward to the next value aligned with `align`.
#[inline(always)]
fn align_forward(ptr: *mut u8, align: usize) -> *mut u8 {
    ((ptr as usize + align - 1) & !(align - 1)) as *mut u8
}

#[cfg(test)]
mod tests {

    use std::any::Any;

    use super::*;

    #[test]
    fn heap_lifetime() {
        let my_int;
        {
            my_int = HEAP.allocate(0i32).unwrap();
        }

        assert_eq!(*my_int, 0);
    }
    #[test]
    fn heap_in_place() {
        let big = in HEAP.make_place().unwrap() { [0u8; 8_000_000] };
        assert_eq!(big.len(), 8_000_000);
    }

    #[test]
    fn unsizing() {
        #[derive(Debug)]
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) {
                println!("Boom")
            }
        }

        let my_foo: Allocated<Any, _> = HEAP.allocate(Bomb).unwrap();
        let _: Allocated<Bomb, _> = my_foo.downcast().ok().unwrap();
    }
}<|endoftext|>