<commit_before>//! A library to parse and load configuration files.
//!
//! This library parses and loads configuration files in much the same way as C/C++'s
//! [libconfig](http://www.hyperrealm.com/libconfig/). At this time, it can only read and load
//! configurations, but future plans include a much richer user API to allow other forms of
//! interaction, such as manipulating values, writing the current configuration to a file, etc.
//!
//!# Getting started
//!
//! A configuration file consists of a group of settings. A setting is a key/value pair, where the
//! key is a string of the form `[a-zA-Z][-a-zA-Z0-9_]*`, and the value is anything represented by
//! `types::Value`. In a configuration file, setting/value pairs are written as
//! `setting_name = value;`. Possible values include primitive integer and floating point types,
//! strings, arrays, lists, etc.
//!
//! The library provides a bunch of methods to read the configuration data in the `reader` module.
//! The possibilities include reading from a string, from a file, or from anything that implements
//! the `Read` trait.
//!
//! As of now, every reader will first attempt to read the whole configuration into memory,
//! and only begins parsing once everything was read.
//!
//! In case of error, the parser returns a `config::error`.
//! On success, the parser returns a `Config`, which can then be used to browse the loaded data.
//!
//! Browsing is typically done with the `lookup_*` methods implemented by `Config`. The `lookup`
//! methods work with *paths*. Essentially, a path unambiguously describes the location of
//! a setting.
//!
//! For example, consider this input configuration file:
//!
//!```ignore
//! title = "My HTTP server";
//! listen_ports = [ 80, 443 ];
//! misc = {
//!     owner = "Chuck Norris";
//!     location = "CA";
//!     contact = {
//!         phone = "415-256-9999";
//!         // This is an array. Arrays start with `[` and end with `]`
//!         // Arrays are homogeneous and can only hold scalar data types.
//!         // See types::ScalarValue for further information
//!         emails = ["chuck@norris.com", "chuck.norris@gmail.com"];
//!     };
//! };
//!```
//!
//! At the top level, we have 3 settings: `title`, `listen_ports` and `misc`. `misc` is itself a
//! group of settings. Each value in this configuration is reachable by a unique path of settings
//! to follow. Each setting in a path is separated by `.`
//!
//! **Example**: The path `misc.contact.phone` identifies the setting with value `415-256-9999`.
//!
//! Array and list types are indexed using `[i]` in a path.
//!
//! **Example**: The path `listen_ports.[1]` identifies the setting with value `443`.
//!
//! **Example**: The path `misc.contact.emails.[0]` identifies the setting with value
//! `chuck@norris.com`
//!
//! Lists, as opposed to arrays, are heterogeneous and can store any data type, including other
//! lists. Here's a setting consisting of a heterogeneous list:
//!
//!```ignore
//! // This is a list. Lists start with `(` and end with `)`
//! // Lists are heterogeneous and can store any data type, including other lists
//! a_setting = ("a string", // The first element is a string
//!              ((1, 2, 3)), // The 2nd element is a list storing a list of 3 integers
//!              misc = { x = 4; y = 3; } // 3rd element: a group
//!             );
//!```
//!
//! Here are some valid paths for this example:
//!
//! `a_setting.[0]` - returns the string `a string`
//!
//! `a_setting.[1].[0].[2]` - returns the integer `3`
//!
//! `a_setting.[2].misc.x` - returns the integer `4`
//!
//! Adjacent string literals separated by whitespace, newlines and / or comments are automatically
//! concatenated.
//!
//! **Example**:
//!
//! ```ignore
//! "a"/* a comment */" string"    " liter"
//!
//! // This is a commment
//!
//!    "al"
//! ```
//!
//! is equivalent to:
//!
//! ```ignore
//! "a string literal"
//! ```
//!
//! See the integration tests (in the `tests/` directory) for sample use cases and more complex
//! examples.
//!
//!# Environment variables
//!
//! The crate has an ability to inject environment variables into the configuration file. That
//! becomes possible using special syntax:
//!
//!  * `$"SOME_ENV_VAR_NAME"::str` to inject the environment variables `SOME_ENV_VAR_NAME` as the string value.
//!    No additiocal changes are made ot the value.
//!  * `$"SOME_ENV_VAR_NAME"::bool` to inject the environment variables `SOME_ENV_VAR_NAME` as the boolean value.
//!    The value `true` or `yes` or `on` or `1` are converted into `true` otherwise into `false`.
//!  * `$"SOME_ENV_VAR_NAME"::int` to inject the environment variables `SOME_ENV_VAR_NAME` as the integer value.
//!    The successfully parsed value is injected as `i32` or `i64`, depending on the format, otherwise `0i32` is injected.
//!  * `$"SOME_ENV_VAR_NAME"::flt` to inject the environment variables `SOME_ENV_VAR_NAME` as the floating value.
//!    The successfully parsed value is injected as `f32` or `f64`, depending on the format, otherwise `0f32` is injected.
//!
//!
//! **Example**:
//!
//! ```ignore
//! #!/bin/sh
//! export LOG_LEVEL=debug
//! ```
//!
//! ```ignore
//! // Configuration file
//! log = {
//!       // Inject (use) the value of the environment variable LOG_LEVEL
//!       level = $"LOG_LEVEL"::str;
//! }
//! ```
//!
//!# Grammar
//!
//! This section describes the configuration input format. The starting rule is `conf`.
//!
//! ```text
//! conf -> __ settings_list __
//!
//! settings_list -> // empty
//!                | setting settings_list
//! setting -> __ name __ (":"|"=") __ value __ ";" __
//!
//! name -> [a-zA-Z][-a-zA-Z0-9_]*
//!
//! value -> scalar_value
//!        | array_value
//!        | list_value
//!        | group_value
//!
//! scalar_value -> boolean_scalar_value
//!               | floating64_scalar_value
//!               | floating32_scalar_value
//!               | integer64_scalar_value
//!               | integer32_scalar_value
//!               | str_scalar_value
//!
//! boolean_scalar_value -> [Tt][Rr][Uu][Ee]
//!                       | [Yy][Ee][Ss]
//!                       | [Ff][Aa][Ll][Ss][Ee]
//!                       | [Nn][Oo]
//!
//! floating64_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?"L"
//!
//! floating32_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?
//!
//! integer32_scalar_value -> [+-]?[0-9]+
//!
//! integer64_scalar_value -> [+-]?[0-9]+"L"
//!
//! str_scalar_value -> __ str_literal __
//!                   | __ str_literal __ str_scalar_value
//!
//! str_literal -> "\"" ([^\"\\]|(("\\r"|"\\n"|"\\t"|"\\\""|"\\\\")))* "\""
//!
//! array_value -> "["
//!                (bool_array |
//!                 flt64_array | flt32_array |
//!                 int64_array | int32_array |
//!                 str_array)
//!                "]"
//!              | "[" __ "]"
//!
//! bool_array -> __ boolean_scalar_value __
//!             | __ boolean_scalar_value __ "," __ bool_array
//!
//! flt64_array -> __ floating64_scalar_value __
//!              | __ floating64_scalar_value __ "," __ flt64_array
//!
//! flt32_array -> __ floating32_scalar_value __
//!              | __ floating32_scalar_value __ "," __ flt32_array
//
//! int64_array -> __ integer64_scalar_value __
//!              | __ integer64_scalar_value __ "," __ int64_array
//!
//! int32_array -> __ integer32_scalar_value __
//!              | __ integer32_scalar_value __ "," __ int32_array
//!
//! str_array -> __ str_scalar_value __
//!            | __ str_scalar_value __ "," __ str_array
//!
//! list_value -> "(" __ ")"
//!             | "(" list_elements ")"
//!
//! list_elements -> __ value __
//!                | __ value __ "," __ list_elements
//!
//! group_value -> "{" settings_list "}"
//!
//! __ -> // empty
//!     | whitespace __
//!     | eol __
//!     | comment __
//!
//! whitespace -> [\s\t]
//!
//! eol -> "\r\n"
//!      | "\n"
//!
//! comment -> single_line_comment
//!          | multi_line_comment
//!
//! single_line_comment -> ("//"|"#")[^\n]*"\n"?
//!
//! multi_line_comment -> "/*"([^*]|"*"[^/])*"*/"
//!
//! ```
//!

#![crate_name = "config"]
#![crate_type = "lib"]
#![warn(missing_docs)]

#[macro_use]
extern crate nom;

mod parser;

pub mod types;
pub mod error;
pub mod reader;
<commit_msg>Update library documentation<commit_after>//! A library to parse and load configuration files.
//!
//! This library parses and loads configuration files in much the same way as C/C++'s
//! [libconfig](http://www.hyperrealm.com/libconfig/). At this time, it can only read and load
//! configurations, but future plans include a much richer user API to allow other forms of
//! interaction, such as manipulating values, writing the current configuration to a file, etc.
//!
//!# Getting started
//!
//! A configuration file consists of a group of settings. A setting is a key/value pair, where the
//! key is a string of the form `[a-zA-Z][-a-zA-Z0-9_]*`, and the value is anything represented by
//! `types::Value`. In a configuration file, setting/value pairs are written as
//! `setting_name = value;`. Possible values include primitive integer and floating point types,
//! strings, arrays, lists, etc.
//!
//! The library provides a bunch of methods to read the configuration data in the `reader` module.
//! The possibilities include reading from a string, from a file, or from anything that implements
//! the `Read` trait.
//!
//! As of now, every reader will first attempt to read the whole configuration into memory,
//! and only begins parsing once everything was read.
//!
//! In case of error, the parser returns a `config::error`.
//! On success, the parser returns a `Config`, which can then be used to browse the loaded data.
//!
//! Browsing is typically done with the `lookup_*` methods implemented by `Config`. The `lookup`
//! methods work with *paths*. Essentially, a path unambiguously describes the location of
//! a setting.
//!
//! For example, consider this input configuration file:
//!
//!```ignore
//! title = "My HTTP server";
//! listen_ports = [ 80, 443 ];
//! misc = {
//!     owner = "Chuck Norris";
//!     location = "CA";
//!     contact = {
//!         phone = "415-256-9999";
//!         // This is an array. Arrays start with `[` and end with `]`
//!         // Arrays are homogeneous and can only hold scalar data types.
//!         // See types::ScalarValue for further information
//!         emails = ["chuck@norris.com", "chuck.norris@gmail.com"];
//!     };
//! };
//!```
//!
//! At the top level, we have 3 settings: `title`, `listen_ports` and `misc`. `misc` is itself a
//! group of settings. Each value in this configuration is reachable by a unique path of settings
//! to follow. Each setting in a path is separated by `.`
//!
//! **Example**: The path `misc.contact.phone` identifies the setting with value `415-256-9999`.
//!
//! Array and list types are indexed using `[i]` in a path.
//!
//! **Example**: The path `listen_ports.[1]` identifies the setting with value `443`.
//!
//! **Example**: The path `misc.contact.emails.[0]` identifies the setting with value
//! `chuck@norris.com`
//!
//! Lists, as opposed to arrays, are heterogeneous and can store any data type, including other
//! lists. Here's a setting consisting of a heterogeneous list:
//!
//!```ignore
//! // This is a list. Lists start with `(` and end with `)`
//! // Lists are heterogeneous and can store any data type, including other lists
//! a_setting = ("a string", // The first element is a string
//!              ((1, 2, 3)), // The 2nd element is a list storing a list of 3 integers
//!              misc = { x = 4; y = 3; } // 3rd element: a group
//!             );
//!```
//!
//! Here are some valid paths for this example:
//!
//! `a_setting.[0]` - returns the string `a string`
//!
//! `a_setting.[1].[0].[2]` - returns the integer `3`
//!
//! `a_setting.[2].misc.x` - returns the integer `4`
//!
//! Adjacent string literals separated by whitespace, newlines and / or comments are automatically
//! concatenated.
//!
//! **Example**:
//!
//! ```ignore
//! "a"/* a comment */" string"    " liter"
//!
//! // This is a commment
//!
//!    "al"
//! ```
//!
//! is equivalent to:
//!
//! ```ignore
//! "a string literal"
//! ```
//!
//! See the integration tests (in the `tests/` directory) for sample use cases and more complex
//! examples.
//!
//!# Environment variables
//!
//! The crate has an ability to inject environment variables into the configuration file. That
//! becomes possible using special syntax:
//!
//!  * `$"SOME_ENV_VAR_NAME"::str` to inject the environment variables `SOME_ENV_VAR_NAME` as the string value.
//!    No additiocal changes are made ot the value.
//!  * `$"SOME_ENV_VAR_NAME"::bool` to inject the environment variable `SOME_ENV_VAR_NAME` as the boolean value.
//!    The value `true` or `yes` or `on` or `1` are converted into `true` otherwise into `false`.
//!  * `$"SOME_ENV_VAR_NAME"::int` to inject the environment variable `SOME_ENV_VAR_NAME` as the integer value.
//!    The successfully parsed value is injected as `i32` or `i64`, depending on the format, otherwise `0i32` is injected.
//!  * `$"SOME_ENV_VAR_NAME"::flt` to inject the environment variable `SOME_ENV_VAR_NAME` as the floating value.
//!    The successfully parsed value is injected as `f32` or `f64`, depending on the format, otherwise `0f32` is injected.
//!  * `$"SOME_ENV_VAR_NAME"::auto` or `$"SOME_ENV_VAR_NAME"` to inject the environment variable `SOME_ENV_VAR_NAME`
//!    and resolve the type automatically. Rules of the type auto-resolution:
//!    - If the value is *True* or *Yes* or *On* then the result type is `boolean True`;
//!    - If the value is *False* or *No* or *Off* then the result type is `boolean False`;
//!    - If the value is floating then the result type is `floating`;
//!    - If the value is integer then the result type is `integer`;
//!    - Otherwise the result is `string` value.
//!
//!**Example**:
//!
//! ```ignore
//! #!/bin/sh
//! export LOG_LEVEL=debug
//! ```
//!
//! ```ignore
//! // Configuration file
//! log = {
//!       // Inject (use) the value of the environment variable LOG_LEVEL
//!       level = $"LOG_LEVEL"::str;
//! }
//! ```
//!
//!# Grammar
//!
//! This section describes the configuration input format. The starting rule is `conf`.
//!
//! ```text
//! conf -> __ settings_list __
//!
//! settings_list -> // empty
//!                | setting settings_list
//! setting -> __ name __ (":"|"=") __ value __ ";" __
//!
//! name -> [a-zA-Z][-a-zA-Z0-9_]*
//!
//! value -> scalar_value
//!        | array_value
//!        | list_value
//!        | group_value
//!
//! scalar_value -> boolean_scalar_value
//!               | floating64_scalar_value
//!               | floating32_scalar_value
//!               | integer64_scalar_value
//!               | integer32_scalar_value
//!               | str_scalar_value
//!
//! boolean_scalar_value -> [Tt][Rr][Uu][Ee]
//!                       | [Yy][Ee][Ss]
//!                       | [Ff][Aa][Ll][Ss][Ee]
//!                       | [Nn][Oo]
//!
//! floating64_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?"L"
//!
//! floating32_scalar_value -> [+-]?([0-9]+\.[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?
//!
//! integer32_scalar_value -> [+-]?[0-9]+
//!
//! integer64_scalar_value -> [+-]?[0-9]+"L"
//!
//! str_scalar_value -> __ str_literal __
//!                   | __ str_literal __ str_scalar_value
//!
//! str_literal -> "\"" ([^\"\\]|(("\\r"|"\\n"|"\\t"|"\\\""|"\\\\")))* "\""
//!
//! array_value -> "["
//!                (bool_array |
//!                 flt64_array | flt32_array |
//!                 int64_array | int32_array |
//!                 str_array)
//!                "]"
//!              | "[" __ "]"
//!
//! bool_array -> __ boolean_scalar_value __
//!             | __ boolean_scalar_value __ "," __ bool_array
//!
//! flt64_array -> __ floating64_scalar_value __
//!              | __ floating64_scalar_value __ "," __ flt64_array
//!
//! flt32_array -> __ floating32_scalar_value __
//!              | __ floating32_scalar_value __ "," __ flt32_array
//
//! int64_array -> __ integer64_scalar_value __
//!              | __ integer64_scalar_value __ "," __ int64_array
//!
//! int32_array -> __ integer32_scalar_value __
//!              | __ integer32_scalar_value __ "," __ int32_array
//!
//! str_array -> __ str_scalar_value __
//!            | __ str_scalar_value __ "," __ str_array
//!
//! list_value -> "(" __ ")"
//!             | "(" list_elements ")"
//!
//! list_elements -> __ value __
//!                | __ value __ "," __ list_elements
//!
//! group_value -> "{" settings_list "}"
//!
//! __ -> // empty
//!     | whitespace __
//!     | eol __
//!     | comment __
//!
//! whitespace -> [\s\t]
//!
//! eol -> "\r\n"
//!      | "\n"
//!
//! comment -> single_line_comment
//!          | multi_line_comment
//!
//! single_line_comment -> ("//"|"#")[^\n]*"\n"?
//!
//! multi_line_comment -> "/*"([^*]|"*"[^/])*"*/"
//!
//! ```
//!

#![crate_name = "config"]
#![crate_type = "lib"]
#![warn(missing_docs)]

#[macro_use]
extern crate nom;

mod parser;

pub mod types;
pub mod error;
pub mod reader;
<|endoftext|>


<commit_before>
extern crate hyper;
extern crate url;

use std::io::{Read, Write};
use url::{Url, ParseError};
use hyper::error::Error;
use hyper::client::Request;
use hyper::method::Method;
pub use hyper::header::*;

pub struct Client<'a, H: Header + HeaderFormat> {
    url: Url,
    params: Option<Vec<(&'a str, &'a str)>>,
    body: Option<&'a str>,
    headers: Option<Vec<H>>,
}

impl<'a, H: Header + HeaderFormat> Client<'a, H> {
    pub fn new(url_str: &'a str) -> Result<Client<'a, H>, ParseError> {
        let url = try!(Url::parse(url_str));
        Ok(Client { url: url, params: None, body: None, headers: None })
    }

    pub fn param(&'a mut self, param: (&'a str, &'a str)) -> &'a mut Client<'a, H> {
        if let Some(ref mut p) = self.params {
            p.push(param);
        }
        else
        {
            let mut v = Vec::new();
            v.push(param);
            self.params = Some(v);
        }
        self
    }

    pub fn body(&'a mut self, body: &'a str) -> &'a mut Client<'a, H> {
        self.body = Some(body);
        self
    }

    pub fn header(&'a mut self, header: H) -> &'a mut Client<'a, H> {
        if let Some(ref mut h) = self.headers {
            h.push(header);
        }
        else
        {
            let mut v = Vec::new();
            v.push(header);
            self.headers = Some(v);
        }
        self
    }

    pub fn get(&mut self) -> Result<String, Error> {
        let mut url = self.url.clone();

        if let Some(ref params) = self.params {
            url.set_query_from_pairs(params.into_iter().map(|&x| x));
        }

        let mut req = try!(Request::new(Method::Get, url));

        if let Some(headers) = self.headers.as_ref() {
           for header in headers {
               req.headers_mut().set(header.clone());
           }
       }

        let mut req = try!(req.start());

        if let Some(body) = self.body {
           req.write(body.as_bytes());
       }

        let mut resp = try!(req.send());

        let mut response_string = String::new();
        resp.read_to_string(&mut response_string);
        Ok(response_string)
    }
}
<commit_msg>Get rid of warnings.<commit_after>
extern crate hyper;
extern crate url;

use std::io::{Read, Write};
use url::{Url, ParseError};
use hyper::error::Error;
use hyper::client::Request;
use hyper::method::Method;
pub use hyper::header::*;

pub struct Client<'a, H: Header + HeaderFormat> {
    url: Url,
    params: Option<Vec<(&'a str, &'a str)>>,
    body: Option<&'a str>,
    headers: Option<Vec<H>>,
}

impl<'a, H: Header + HeaderFormat> Client<'a, H> {
    pub fn new(url_str: &'a str) -> Result<Client<'a, H>, ParseError> {
        let url = try!(Url::parse(url_str));
        Ok(Client { url: url, params: None, body: None, headers: None })
    }

    pub fn param(&'a mut self, param: (&'a str, &'a str)) -> &'a mut Client<'a, H> {
        if let Some(ref mut p) = self.params {
            p.push(param);
        }
        else
        {
            let mut v = Vec::new();
            v.push(param);
            self.params = Some(v);
        }
        self
    }

    pub fn body(&'a mut self, body: &'a str) -> &'a mut Client<'a, H> {
        self.body = Some(body);
        self
    }

    pub fn header(&'a mut self, header: H) -> &'a mut Client<'a, H> {
        if let Some(ref mut h) = self.headers {
            h.push(header);
        }
        else
        {
            let mut v = Vec::new();
            v.push(header);
            self.headers = Some(v);
        }
        self
    }

    pub fn get(&mut self) -> Result<String, Error> {
        let mut url = self.url.clone();

        if let Some(ref params) = self.params {
            url.set_query_from_pairs(params.into_iter().map(|&x| x));
        }

        let mut req = try!(Request::new(Method::Get, url));

        if let Some(headers) = self.headers.as_ref() {
           for header in headers {
               req.headers_mut().set(header.clone());
           }
       }

        let mut req = try!(req.start());

        if let Some(body) = self.body {
           try!(req.write_all(body.as_bytes()));
       }

        let mut resp = try!(req.send());

        let mut response_string = String::new();
        try!(resp.read_to_string(&mut response_string));
        Ok(response_string)
    }
}
<|endoftext|>


<commit_before>extern crate cards;

use std::cmp::{Ord};

use cards::card::{Card};

#[derive(Debug, PartialEq)]
#[derive(Eq, Hash)]
#[derive(PartialOrd, Ord)]
pub enum HandRankClass {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

// find maximum value to determine best hand
// larger values are "better", inverting the Cactus Kev convention
pub type HandRank = u16;

pub const HAND_RANK_COUNT : u16 = 7462;

// assumes there are HAND_RANK_COUNT distinct hand ranks, where the
// largest are the most valuable. An inversion of cactus kev's ranks
pub fn hand_rank_to_class(val: &HandRank) -> HandRankClass {
    match *val {
        x if x <= HAND_RANK_COUNT-6185 => HandRankClass::HighCard,
        x if x <= HAND_RANK_COUNT-3325 => HandRankClass::OnePair,
        x if x <= HAND_RANK_COUNT-2467 => HandRankClass::TwoPair,
        x if x <= HAND_RANK_COUNT-1609 => HandRankClass::ThreeOfAKind,
        x if x <= HAND_RANK_COUNT-1599 => HandRankClass::Straight,
        x if x <= HAND_RANK_COUNT-322  => HandRankClass::Flush,
        x if x <= HAND_RANK_COUNT-166  => HandRankClass::FullHouse,
        x if x <= HAND_RANK_COUNT-10   => HandRankClass::FourOfAKind,
        x if x <= HAND_RANK_COUNT-0    => HandRankClass::StraightFlush,
        _                              => panic!("Unexpected hand rank value!")
    }
}

pub enum CardSlot {
    Empty,
    Dealt(Card),
}

impl CardSlot {
    pub fn expect_borrow(&self) -> &Card {
        match self {
            &CardSlot::Empty => panic!("You are trying to borrow a non-dealt card"),
            &CardSlot::Dealt(ref x) => x
        }
    }
}

pub struct HandCards(pub CardSlot, pub CardSlot);
pub struct CommunityCards(pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot);
<commit_msg>Glorious off-by-one.<commit_after>extern crate cards;

use std::cmp::{Ord};

use cards::card::{Card};

#[derive(Debug, PartialEq)]
#[derive(Eq, Hash)]
#[derive(PartialOrd, Ord)]
pub enum HandRankClass {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

// find maximum value to determine best hand
// larger values are "better", inverting the Cactus Kev convention
pub type HandRank = u16;

pub const HAND_RANK_COUNT : u16 = 7462;

// assumes there are HAND_RANK_COUNT distinct hand ranks, where the
// largest are the most valuable. An inversion of cactus kev's ranks
pub fn hand_rank_to_class(val: &HandRank) -> HandRankClass {
    match *val {
        x if x < HAND_RANK_COUNT-6185 => HandRankClass::HighCard,
        x if x < HAND_RANK_COUNT-3325 => HandRankClass::OnePair,
        x if x < HAND_RANK_COUNT-2467 => HandRankClass::TwoPair,
        x if x < HAND_RANK_COUNT-1609 => HandRankClass::ThreeOfAKind,
        x if x < HAND_RANK_COUNT-1599 => HandRankClass::Straight,
        x if x < HAND_RANK_COUNT-322  => HandRankClass::Flush,
        x if x < HAND_RANK_COUNT-166  => HandRankClass::FullHouse,
        x if x < HAND_RANK_COUNT-10   => HandRankClass::FourOfAKind,
        x if x < HAND_RANK_COUNT-0    => HandRankClass::StraightFlush,
        _                              => panic!("Unexpected hand rank value!")
    }
}

pub enum CardSlot {
    Empty,
    Dealt(Card),
}

impl CardSlot {
    pub fn expect_borrow(&self) -> &Card {
        match self {
            &CardSlot::Empty => panic!("You are trying to borrow a non-dealt card"),
            &CardSlot::Dealt(ref x) => x
        }
    }
}

pub struct HandCards(pub CardSlot, pub CardSlot);
pub struct CommunityCards(pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot);
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Meta parsing and encoding for data oriented design

extern crate read_token;
extern crate range;

pub use whitespace::{ Whitespace, WHITESPACE };
pub use parse_error_handler::{ ParseErrorHandler, ParseStdErr };
pub use parse_error::ParseError;
pub use ty::Type;
pub use token::Token;
pub use select::Select;
pub use parameter::Parameter;
pub use optional::Optional;
pub use until_any_or_whitespace::UntilAnyOrWhitespace;
pub use text::Text;
pub use number::Number;
pub use rule::Rule;
pub use meta_reader::MetaReader;

use std::rc::Rc;
use std::cell::RefCell;

mod parse_error;
mod parse_error_handler;
mod ty;
mod token;
mod whitespace;
mod select;
mod parameter;
mod optional;
mod until_any_or_whitespace;
mod text;
mod number;
mod rule;
mod meta_reader;

/// Represents a data structure to read into.
pub struct Struct<'a> {
    /// The fields of a struct.
    pub fields: &'a mut [Data<'a>],
}

/// Allocated data for reading.
pub enum Data<'a> {
    /// Hash a f64 property.
    F64(&'a str, &'a mut f64),
    /// Has a bool property.
    Bool(&'a str, &'a mut bool),
    /// Has a string property.
    String(&'a str, &'a mut String),
    /// Has a sub node.
    Node(&'a str),
}

/// Represents meta data.
pub enum MetaData<'a> {
    /// Starts node.
    StartNode(&'a str),
    /// Ends node.
    EndNode,
    /// Sets bool property.
    Bool(&'a str, bool),
    /// Sets f64 property.
    F64(&'a str, f64),
    /// Sets string property.
    String(&'a str, String),
}

/// Implemented by meta writers.
pub trait MetaWriter {
    /// Starts encoding a node.
    fn start_node(&mut self, name: &str);
    /// Ends encoding a node.
    fn end_node(&mut self, name: &str);
    /// Get bool property.
    fn get_as_bool(&mut self, name: &str) -> Option<bool>;
    /// Get str property.
    fn get_as_str<F, U>(&mut self, name: &str, f: F) -> Option<U>
        where F: FnOnce(&str) -> U;
    /// Get f64 property.
    fn get_as_f64(&mut self, name: &str) -> Option<f64>;
}

#[inline(always)]
fn update<'a>(range: range::Range, chars: &mut &'a [char], offset: &mut usize) {
    let next_offset = range.next_offset();
    *chars = &chars[next_offset - *offset..];
    *offset = next_offset;
}

/// Used by meta readers to handle or forward a state.
/// This makes it easier to write generic meta readers wrapping a sub reader.
pub enum CommandState<T, U> {
    /// Handle state.
    Handle(T),
    /// Forward command to sub meta reader.
    Forward(U),
}
<commit_msg>Added `Maybe` data<commit_after>#![deny(missing_docs)]

//! Meta parsing and encoding for data oriented design

extern crate read_token;
extern crate range;

pub use whitespace::{ Whitespace, WHITESPACE };
pub use parse_error_handler::{ ParseErrorHandler, ParseStdErr };
pub use parse_error::ParseError;
pub use ty::Type;
pub use token::Token;
pub use select::Select;
pub use parameter::Parameter;
pub use optional::Optional;
pub use until_any_or_whitespace::UntilAnyOrWhitespace;
pub use text::Text;
pub use number::Number;
pub use rule::Rule;
pub use meta_reader::MetaReader;

use std::rc::Rc;
use std::cell::RefCell;

mod parse_error;
mod parse_error_handler;
mod ty;
mod token;
mod whitespace;
mod select;
mod parameter;
mod optional;
mod until_any_or_whitespace;
mod text;
mod number;
mod rule;
mod meta_reader;

/// Represents a data structure to read into.
pub struct Struct<'a> {
    /// The fields of a struct.
    pub fields: &'a mut [Data<'a>],
}

/// Allocated data for reading.
/// This also tells the meta parser which properties are required
/// and which properties that are optional.
pub enum Data<'a> {
    /// Has a f64 property.
    F64(&'a str, &'a mut f64),
    /// Has a bool property.
    Bool(&'a str, &'a mut bool),
    /// Has a string property.
    String(&'a str, &'a mut String),
    /// Has a sub node.
    Node(&'a str),
    /// Has an optional f64 property.
    MaybeF64(&'a str, &'a mut Option<f64>),
    /// Has an optional bool property.
    MaybeBool(&'a str, &'a mut Option<bool>),
    /// Has an optional string property.
    MaybeString(&'a str, &'a mut Option<String>),
    /// Has an optional sub node.
    MaybeNode(&'a str),
}

/// Represents meta data.
pub enum MetaData<'a> {
    /// Starts node.
    StartNode(&'a str),
    /// Ends node.
    EndNode,
    /// Sets bool property.
    Bool(&'a str, bool),
    /// Sets f64 property.
    F64(&'a str, f64),
    /// Sets string property.
    String(&'a str, String),
}

/// Implemented by meta writers.
pub trait MetaWriter {
    /// Starts encoding a node.
    fn start_node(&mut self, name: &str);
    /// Ends encoding a node.
    fn end_node(&mut self, name: &str);
    /// Get bool property.
    fn get_as_bool(&mut self, name: &str) -> Option<bool>;
    /// Get str property.
    fn get_as_str<F, U>(&mut self, name: &str, f: F) -> Option<U>
        where F: FnOnce(&str) -> U;
    /// Get f64 property.
    fn get_as_f64(&mut self, name: &str) -> Option<f64>;
}

#[inline(always)]
fn update<'a>(range: range::Range, chars: &mut &'a [char], offset: &mut usize) {
    let next_offset = range.next_offset();
    *chars = &chars[next_offset - *offset..];
    *offset = next_offset;
}

/// Used by meta readers to handle or forward a state.
/// This makes it easier to write generic meta readers wrapping a sub reader.
pub enum CommandState<T, U> {
    /// Handle state.
    Handle(T),
    /// Forward command to sub meta reader.
    Forward(U),
}
<|endoftext|>


<commit_before>//! Logging module

extern crate time;
extern crate libc;
use self::libc::{c_void};

use std::collections::vec_deque::VecDeque;
use std::fmt;
use std::io::{Write, Read, Seek, BufRead};
use std;

use utils;

pub enum FilterLog {
    None,
    Last(time::Tm)
}

impl FilterLog {
    ///Checks if given element is within allowed time range
    #[inline]
    pub fn check(&self, time: &time::Tm) -> bool {
        match *self {
            FilterLog::None => true,
            FilterLog::Last(from) => from < *time,
        }
    }
}

impl fmt::Display for FilterLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            FilterLog::None => write!(f, "None"),
            FilterLog::Last(from) => write!(f, "Last({})", from.strftime("%x %X.%f").unwrap()),
        }
    }
}

pub struct IrcLog {
    inner: VecDeque<IrcEntry>,
    fs_buf: std::fs::File
}

impl IrcLog {
    /// Creates log with default capacity 500.
    #[inline(always)]
    pub fn new() -> IrcLog {
        IrcLog {
            inner: VecDeque::with_capacity(500),
            //Open file log once for both write/read.
            //To read/write correctly be sure to .seek() at needed position
            fs_buf: std::fs::OpenOptions::new().read(true)
                                               .write(true)
                                               .create(true)
                                               .open("vndis.log")
                                               .unwrap()
        }
    }

    ///Dumps all logs except for last 20
    fn buff_to_file(&mut self) {
        let len = self.inner.len();

        if len <= 20 {return;}

        self.fs_buf.seek(std::io::SeekFrom::End(0)).unwrap();
        //range is exclusive at the end
        for _ in 0..len-19 {
            self.fs_buf.write_fmt(format_args!("{}\n", self.inner.pop_front().unwrap())).unwrap();
        }
        self.fs_buf.flush().unwrap()
    }

    ///Dumps all logs except for last 20
    fn dump_to_file(&mut self) {
        let len = self.inner.len();

        if len == 0 {return;}

        self.fs_buf.seek(std::io::SeekFrom::End(0)).unwrap();
        //range is exclusive at the end
        for _ in 0..len {
            self.fs_buf.write_fmt(format_args!("{}\n", self.inner.pop_front().unwrap())).unwrap();
        }
        self.fs_buf.flush().unwrap()
    }

    #[inline(always)]
    /// Adds entry to log.
    pub fn add(&mut self, entry: IrcEntry) {
        if self.len() >= self.capacity() {
            self.buff_to_file();
        }
        self.inner.push_back(entry);
    }

    #[inline]
    /// Reads all/filtered entries from underlying file buffer.
    pub fn fs_read(&mut self, filter: &FilterLog) -> String {
        if self.fs_buf.metadata().unwrap().len() == 0 {
            return "".to_string();
        }

        self.fs_buf.seek(std::io::SeekFrom::Start(0)).unwrap();

        let reader = std::io::BufReader::new(&mut self.fs_buf);
        let lines = reader.lines();

        //Let's try to peek the number of lines for effective allocation
        let acc_str = if let (_, Some(len)) = lines.size_hint() {
            String::with_capacity(len*50)
        }
        else {
            String::new()
        };

        lines.fold(acc_str, |acc, line| {
            const DATA_START: usize = 1;
            const DATA_END: usize = 28;
            let line = line.unwrap();
            let time_stamp = time::strptime(&line[DATA_START..DATA_END], "%x %X.%f").unwrap();

            if filter.check(&time_stamp) {
                acc + &format!("{}\n", line)
            }
            else {
                acc
            }
        })
    }

    #[inline(always)]
    /// Returns iterator over underlying buffer.
    pub fn iter(&self) -> std::collections::vec_deque::Iter<IrcEntry> {
        self.inner.iter()
    }

    #[inline(always)]
    /// Returns formatted string with log inner entries.
    pub fn read_to_string(&self, filter: &FilterLog) -> String {
        let log_size = self.len();

        if log_size == 0 {
            "".to_string()
        }
        else {
            self.iter()
                .filter(|elem| filter.check(&elem.time()))
                .fold(String::with_capacity(log_size*50), |acc, item| acc + &format!("{}\n", item))
        }
    }

    #[inline(always)]
    ///Returns content of file and heap buffers.
    pub fn get_all(&mut self, filter: &FilterLog) -> String {
        format!("{}{}", self.fs_read(filter), self.read_to_string(filter))
    }

    #[inline(always)]
    pub fn back(&self) -> Option<&IrcEntry> {
        self.inner.back()
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    #[inline(always)]
    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    ///Returns size of log in bytes.
    #[inline(always)]
    pub fn heap_size(&self) -> usize {
        self.iter().fold(0, |n, elem| n + elem.heap_size()) +
        std::mem::size_of::<VecDeque<IrcEntry>>() +
        std::mem::size_of::<std::fs::File>()
    }
}

impl fmt::Display for IrcLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let heap_size = self.heap_size() as f32;
        write!(f, "Log(len={}, size={:.3}kb)", self.len(), heap_size/1024.0)
    }
}

impl Drop for IrcLog {
    fn drop(&mut self) {
        self.dump_to_file();
    }
}

#[derive(Clone, Debug)]
pub struct IrcEntry {
    time: time::Tm,
    nickname: String,
    message: String
}

impl IrcEntry {
    #[inline(always)]
    /// Creates new log entry from message and nick
    pub fn new(nick: String, msg: String) -> IrcEntry {
        IrcEntry {
            time: time::now(),
            nickname: nick,
            message: msg,
        }
    }

    #[inline(always)]
    pub fn time(&self) -> time::Tm {
        self.time
    }

    #[inline(always)]
    pub fn nickname(&self) -> &String {
        &self.nickname
    }

    #[inline(always)]
    pub fn message(&self) -> &String {
        &self.message
    }

    #[inline(always)]
    pub fn heap_size(&self) -> usize {
        //there are 11 fields of i32 in Tm.
        std::mem::size_of::<i32>() * 11 +
        utils::heap_size_of(self.nickname().as_ptr() as *const c_void) +
        utils::heap_size_of(self.message().as_ptr() as *const c_void)
    }
}

impl PartialEq for IrcEntry {
    fn eq(&self, right: &IrcEntry) -> bool {
        self.time == right.time
    }

    fn ne(&self, right: &IrcEntry) -> bool {
        self.time != right.time
    }
}

impl fmt::Display for IrcEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "[{}] <{}> {}", self.time.strftime("%x %X.%f").unwrap(), self.nickname, self.message)
    }
}

#[cfg(test)]
mod tests {
    extern crate time;
    use super::*;
    use std;

    #[test]
    fn test_irc_entry() {
        let entry = IrcEntry::new("Kuu".to_string(), "nya nya!".to_string());

        assert!(entry.nickname == "Kuu");
        assert!(entry.message == "nya nya!");
    }

    #[test]
    fn test_filter_log() {
        let time_now    = time::now();
        let time_before = time_now - time::Duration::minutes(10);
        let time_after  = time_now + time::Duration::minutes(10);
        let no_filter   = FilterLog::None;
        let filter_now  = FilterLog::Last(time_now);

        assert!(no_filter.check(&time_before));
        assert!(format!("{}", no_filter) == "None");

        assert!(!filter_now.check(&time_before));
        assert!(filter_now.check(&time_after));
        assert!(format!("{}", filter_now) == format!("Last({})", time_now.strftime("%x %X.%f").unwrap()));
    }

    macro_rules! is_file {
        ($path:expr) => { std::fs::metadata($path).ok().map_or(false, |data| data.is_file()); };
    }

    #[test]
    fn test_irc_log() {
        let filter = FilterLog::None;
        std::env::set_current_dir(std::env::current_exe().unwrap().parent().unwrap())
                  .unwrap_or_else(|err| panic!("cannot enter my own directory :(. Err={}", err));

        let mut log = IrcLog::new();
        let old_capacity = log.capacity();

        assert!(is_file!("vndis.log"));
        assert!(log.len() == 0);
        assert!(log.read_to_string(&filter).is_empty());
        assert!(log.fs_read(&filter).is_empty());

        let flood_entry = IrcEntry::new("Kuu".to_string(), "nya nya!".to_string());
        let rare_entry = IrcEntry::new("Kuu".to_string(), "...".to_string());

        log.add(flood_entry.clone());
        log.add(rare_entry.clone());

        let mut expect_str = format!("{}\n{}\n", flood_entry, rare_entry);
        assert!(log.len() == 2);
        assert!(log.back() == Some(&rare_entry));
        assert!(log.read_to_string(&filter) == expect_str);
        assert!(log.fs_read(&filter).is_empty());

        for i in 0..old_capacity+1 {
            let entry = IrcEntry::new(format!("Kuu{}", i), format!("i={}", i));
            expect_str = expect_str + &format!("{}\n", &entry);
            log.add(entry);
        }

        assert!(log.capacity() == old_capacity);
        assert!(log.back().unwrap().nickname == format!("Kuu{}", old_capacity));
        assert!(log.back().unwrap().message == format!("i={}", old_capacity));
        assert!(log.get_all(&filter) == expect_str);

        drop(log);
        std::fs::remove_file("vndis.log").unwrap();
    }
}
<commit_msg>Introduce TIME_FORMAT constant<commit_after>//! Logging module

extern crate time;
extern crate libc;
use self::libc::{c_void};

use std::collections::vec_deque::VecDeque;
use std::fmt;
use std::io::{Write, Read, Seek, BufRead};
use std;

use utils;

const TIME_FORMAT: &'static str = "%x %X";

pub enum FilterLog {
    None,
    Last(time::Tm)
}

impl FilterLog {
    ///Checks if given element is within allowed time range
    #[inline]
    pub fn check(&self, time: &time::Tm) -> bool {
        match *self {
            FilterLog::None => true,
            FilterLog::Last(from) => from < *time,
        }
    }
}

impl fmt::Display for FilterLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            FilterLog::None => write!(f, "None"),
            FilterLog::Last(from) => write!(f, "Last({})", from.strftime(TIME_FORMAT).unwrap()),
        }
    }
}

pub struct IrcLog {
    inner: VecDeque<IrcEntry>,
    fs_buf: std::fs::File
}

impl IrcLog {
    /// Creates log with default capacity 500.
    #[inline(always)]
    pub fn new() -> IrcLog {
        IrcLog {
            inner: VecDeque::with_capacity(500),
            //Open file log once for both write/read.
            //To read/write correctly be sure to .seek() at needed position
            fs_buf: std::fs::OpenOptions::new().read(true)
                                               .write(true)
                                               .create(true)
                                               .open("vndis.log")
                                               .unwrap()
        }
    }

    ///Dumps all logs except for last 20
    fn buff_to_file(&mut self) {
        let len = self.inner.len();

        if len <= 20 {return;}

        self.fs_buf.seek(std::io::SeekFrom::End(0)).unwrap();
        //range is exclusive at the end
        for _ in 0..len-19 {
            self.fs_buf.write_fmt(format_args!("{}\n", self.inner.pop_front().unwrap())).unwrap();
        }
        self.fs_buf.flush().unwrap()
    }

    ///Dumps all logs except for last 20
    fn dump_to_file(&mut self) {
        let len = self.inner.len();

        if len == 0 {return;}

        self.fs_buf.seek(std::io::SeekFrom::End(0)).unwrap();
        //range is exclusive at the end
        for _ in 0..len {
            self.fs_buf.write_fmt(format_args!("{}\n", self.inner.pop_front().unwrap())).unwrap();
        }
        self.fs_buf.flush().unwrap()
    }

    #[inline(always)]
    /// Adds entry to log.
    pub fn add(&mut self, entry: IrcEntry) {
        if self.len() >= self.capacity() {
            self.buff_to_file();
        }
        self.inner.push_back(entry);
    }

    #[inline]
    /// Reads all/filtered entries from underlying file buffer.
    pub fn fs_read(&mut self, filter: &FilterLog) -> String {
        if self.fs_buf.metadata().unwrap().len() == 0 {
            return "".to_string();
        }

        self.fs_buf.seek(std::io::SeekFrom::Start(0)).unwrap();

        let reader = std::io::BufReader::new(&mut self.fs_buf);
        let lines = reader.lines();

        //Let's try to peek the number of lines for effective allocation
        let acc_str = if let (_, Some(len)) = lines.size_hint() {
            String::with_capacity(len*50)
        }
        else {
            String::new()
        };

        lines.fold(acc_str, |acc, line| {
            const DATA_START: usize = 1;
            const DATA_END: usize = 28;
            let line = line.unwrap();
            let time_stamp = time::strptime(&line[DATA_START..DATA_END], TIME_FORMAT).unwrap();

            if filter.check(&time_stamp) {
                acc + &format!("{}\n", line)
            }
            else {
                acc
            }
        })
    }

    #[inline(always)]
    /// Returns iterator over underlying buffer.
    pub fn iter(&self) -> std::collections::vec_deque::Iter<IrcEntry> {
        self.inner.iter()
    }

    #[inline(always)]
    /// Returns formatted string with log inner entries.
    pub fn read_to_string(&self, filter: &FilterLog) -> String {
        let log_size = self.len();

        if log_size == 0 {
            "".to_string()
        }
        else {
            self.iter()
                .filter(|elem| filter.check(&elem.time()))
                .fold(String::with_capacity(log_size*50), |acc, item| acc + &format!("{}\n", item))
        }
    }

    #[inline(always)]
    ///Returns content of file and heap buffers.
    pub fn get_all(&mut self, filter: &FilterLog) -> String {
        format!("{}{}", self.fs_read(filter), self.read_to_string(filter))
    }

    #[inline(always)]
    pub fn back(&self) -> Option<&IrcEntry> {
        self.inner.back()
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    #[inline(always)]
    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    ///Returns size of log in bytes.
    #[inline(always)]
    pub fn heap_size(&self) -> usize {
        self.iter().fold(0, |n, elem| n + elem.heap_size()) +
        std::mem::size_of::<VecDeque<IrcEntry>>() +
        std::mem::size_of::<std::fs::File>()
    }
}

impl fmt::Display for IrcLog {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let heap_size = self.heap_size() as f32;
        write!(f, "Log(len={}, size={:.3}kb)", self.len(), heap_size/1024.0)
    }
}

impl Drop for IrcLog {
    fn drop(&mut self) {
        self.dump_to_file();
    }
}

#[derive(Clone, Debug)]
pub struct IrcEntry {
    time: time::Tm,
    nickname: String,
    message: String
}

impl IrcEntry {
    #[inline(always)]
    /// Creates new log entry from message and nick
    pub fn new(nick: String, msg: String) -> IrcEntry {
        IrcEntry {
            time: time::now(),
            nickname: nick,
            message: msg,
        }
    }

    #[inline(always)]
    pub fn time(&self) -> time::Tm {
        self.time
    }

    #[inline(always)]
    pub fn nickname(&self) -> &String {
        &self.nickname
    }

    #[inline(always)]
    pub fn message(&self) -> &String {
        &self.message
    }

    #[inline(always)]
    pub fn heap_size(&self) -> usize {
        //there are 11 fields of i32 in Tm.
        std::mem::size_of::<i32>() * 11 +
        utils::heap_size_of(self.nickname().as_ptr() as *const c_void) +
        utils::heap_size_of(self.message().as_ptr() as *const c_void)
    }
}

impl PartialEq for IrcEntry {
    fn eq(&self, right: &IrcEntry) -> bool {
        self.time == right.time
    }

    fn ne(&self, right: &IrcEntry) -> bool {
        self.time != right.time
    }
}

impl fmt::Display for IrcEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "[{}] <{}> {}", self.time.strftime(TIME_FORMAT).unwrap(), self.nickname, self.message)
    }
}

#[cfg(test)]
mod tests {
    extern crate time;
    use super::*;
    use std;

    #[test]
    fn test_irc_entry() {
        let entry = IrcEntry::new("Kuu".to_string(), "nya nya!".to_string());

        assert!(entry.nickname == "Kuu");
        assert!(entry.message == "nya nya!");
    }

    #[test]
    fn test_filter_log() {
        let time_now    = time::now();
        let time_before = time_now - time::Duration::minutes(10);
        let time_after  = time_now + time::Duration::minutes(10);
        let no_filter   = FilterLog::None;
        let filter_now  = FilterLog::Last(time_now);

        assert!(no_filter.check(&time_before));
        assert!(format!("{}", no_filter) == "None");

        assert!(!filter_now.check(&time_before));
        assert!(filter_now.check(&time_after));
        assert!(format!("{}", filter_now) == format!("Last({})", time_now.strftime(super::TIME_FORMAT).unwrap()));
    }

    macro_rules! is_file {
        ($path:expr) => { std::fs::metadata($path).ok().map_or(false, |data| data.is_file()); };
    }

    #[test]
    fn test_irc_log() {
        let filter = FilterLog::None;
        std::env::set_current_dir(std::env::current_exe().unwrap().parent().unwrap())
                  .unwrap_or_else(|err| panic!("cannot enter my own directory :(. Err={}", err));

        let mut log = IrcLog::new();
        let old_capacity = log.capacity();

        assert!(is_file!("vndis.log"));
        assert!(log.len() == 0);
        assert!(log.read_to_string(&filter).is_empty());
        assert!(log.fs_read(&filter).is_empty());

        let flood_entry = IrcEntry::new("Kuu".to_string(), "nya nya!".to_string());
        let rare_entry = IrcEntry::new("Kuu".to_string(), "...".to_string());

        log.add(flood_entry.clone());
        log.add(rare_entry.clone());

        let mut expect_str = format!("{}\n{}\n", flood_entry, rare_entry);
        assert!(log.len() == 2);
        assert!(log.back() == Some(&rare_entry));
        assert!(log.read_to_string(&filter) == expect_str);
        assert!(log.fs_read(&filter).is_empty());

        for i in 0..old_capacity+1 {
            let entry = IrcEntry::new(format!("Kuu{}", i), format!("i={}", i));
            expect_str = expect_str + &format!("{}\n", &entry);
            log.add(entry);
        }

        assert!(log.capacity() == old_capacity);
        assert!(log.back().unwrap().nickname == format!("Kuu{}", old_capacity));
        assert!(log.back().unwrap().message == format!("i={}", old_capacity));
        assert!(log.get_all(&filter) == expect_str);

        drop(log);
        std::fs::remove_file("vndis.log").unwrap();
    }
}
<|endoftext|>


<commit_before>//! Functions for mapping over pixels, colors or subpixels of images.

use image::{
    GenericImage,
    ImageBuffer,
    Luma,
    Pixel,
    Primitive,
    Rgb,
    Rgba
};

use definitions::{
    Image
};

/// The type obtained by replacing the channel type of a given Pixel type.
pub trait WithChannel<C: Primitive>: Pixel {
    /// The new pixel type.
    type Pixel: Pixel<Subpixel=C> + 'static;
}

/// Alias to make uses of `WithChannel` less syntactically noisy.
pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Applies f to each subpixel of the input image.
pub fn map_subpixels<I, P, F, S>(image: &I, f: F) -> Image<ChannelMap<P, S>>
    where I: GenericImage<Pixel=P>,
          P: WithChannel<S> + 'static,
          S: Primitive + 'static,
          F: Fn(P::Subpixel) -> S
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<ChannelMap<P, S>, Vec<S>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            let mut out_channels = out.get_pixel_mut(x, y).channels_mut();
            for c in 0..P::channel_count() {
                out_channels[c as usize]
                    = f(unsafe {*image.unsafe_get_pixel(x, y)
                        .channels().get_unchecked(c as usize) });
            }
        }
    }

    out
}

/// Applies f to the color of each pixel in the input image.
pub fn map_colors<I, P, Q, F>(image: &I, f: F) -> Image<Q>
    where I: GenericImage<Pixel=P>,
          P: Pixel,
          Q: Pixel + 'static,
          F: Fn(P) -> Q
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(pix));
            }
        }
    }

    out
}

/// Applies f to the colors of the pixels in the input images.
///
/// Requires `image1` and `image2` to have the same dimensions.
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::{GrayImage, Luma};
/// use imageproc::map::map_colors2;
///
/// let image1 = gray_image!(
///     1, 2,
///     3, 4
/// );
///
/// let image2 = gray_image!(
///     10, 20,
///     30, 40
/// );
///
/// let sum = gray_image!(
///     11, 22,
///     33, 44
/// );
///
/// assert_pixels_eq!(
///     map_colors2(&image1, &image2, |p, q| Luma([p[0] + q[0]])),
///     sum
/// );
/// # }
/// ```
pub fn map_colors2<I, J, P, Q, R, F>(image1: &I, image2: &J, f: F) -> Image<R>
    where I: GenericImage<Pixel=P>,
          J: GenericImage<Pixel=Q>,
          P: Pixel,
          Q: Pixel,
          R: Pixel + 'static,
          F: Fn(P, Q) -> R
{
    assert_eq!(image1.dimensions(), image2.dimensions());

    let (width, height) = image1.dimensions();
    let mut out: ImageBuffer<R, Vec<R::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let p = image1.unsafe_get_pixel(x, y);
                let q = image2.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(p, q));
            }
        }
    }

    out
}

/// Applies f to each pixel in the input image.
pub fn map_pixels<I, P, Q, F>(image: &I, f: F) -> Image<Q>
    where I: GenericImage<Pixel=P>,
          P: Pixel,
          Q: Pixel + 'static,
          F: Fn(u32, u32, P) -> Q
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(x, y, pix));
            }
        }
    }

    out
}

macro_rules! implement_channel_extraction {
    ($extract_name: ident, $embed_name: ident, $idx: expr) => (
        /// Create a grayscale image by extracting a channel of an RGB image.
        pub fn $extract_name<I, C>(image: &I) -> Image<Luma<C>>
            where I: GenericImage<Pixel=Rgb<C>>,
                  C: Primitive + 'static
        {
            map_colors(image, |p| Luma([p[$idx]]))
        }

        /// Create an RGB image by embedding a grayscale image in a single channel.
        pub fn $embed_name<I, C>(image: &I) -> Image<Rgb<C>>
            where I: GenericImage<Pixel=Luma<C>>,
                  C: Primitive + 'static
        {
            map_colors(image, |p| {
                let mut cs = [C::zero(); 3];
                cs[$idx] = p[0];
                Rgb(cs)
            })
        }
    )
}

implement_channel_extraction!(red_channel, as_red_channel, 0);
implement_channel_extraction!(green_channel, as_green_channel, 1);
implement_channel_extraction!(blue_channel, as_blue_channel, 2);

#[cfg(test)]
mod test {
    use super::{
        map_colors,
        map_pixels,
        map_subpixels,
        red_channel,
        green_channel,
        blue_channel,
        as_red_channel,
        as_green_channel,
        as_blue_channel
    };
    use image::Rgb;

    #[test]
    fn test_map_subpixels() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = gray_image_i16!(
            -2i16, -4i16;
            -6i16, -8i16);

        let mapped = map_subpixels(&image, |x| -2 * (x as i16));
        assert_pixels_eq!(mapped, expected);
    }

    #[test]
    fn test_map_colors() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image_i16!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let mapped = map_colors(&image, |p| {
            let intensity = p[0] as i16;
            Rgb([intensity, (2 * intensity), (3 * intensity)])
        });
        assert_pixels_eq!(mapped, expected);
    }

    #[test]
    fn test_map_pixels() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image_i16!(
            [1, 2, 3], [3, 5, 7];
            [4, 7, 10], [6, 10, 14]);

        let mapped = map_pixels(&image, |x, y, p| {
            let intensity = p[0] as i16;
            let offset = (x + y) as i16;
            Rgb([intensity + offset, 2 * intensity + offset, 3 * intensity + offset])
        });
        assert_pixels_eq!(mapped, expected);
    }

    #[test]
    fn test_red_channel() {
        let image = rgb_image!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let expected = gray_image!(
            1, 2;
            3, 4);

        let actual = red_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_green_channel() {
        let image = rgb_image!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let expected = gray_image!(
            2, 4;
            6, 8);

        let actual = green_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_blue_channel() {
        let image = rgb_image!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let expected = gray_image!(
            3, 6;
            9, 12);

        let actual = blue_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_as_red_channel() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image!(
            [1, 0, 0], [2, 0, 0];
            [3, 0, 0], [4, 0, 0]);

        let actual = as_red_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_as_green_channel() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image!(
            [0, 1, 0], [0, 2, 0];
            [0, 3, 0], [0, 4, 0]);

        let actual = as_green_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_as_blue_channel() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image!(
          [0, 0, 1], [0, 0, 2];
          [0, 0, 3], [0, 0, 4]);

        let actual = as_blue_channel(&image);
        assert_pixels_eq!(actual, expected);
    }
}
<commit_msg>Add doctests to functions in map module<commit_after>//! Functions for mapping over pixels, colors or subpixels of images.

use image::{
    GenericImage,
    ImageBuffer,
    Luma,
    Pixel,
    Primitive,
    Rgb,
    Rgba
};

use definitions::Image;

/// The type obtained by replacing the channel type of a given `Pixel` type.
pub trait WithChannel<C: Primitive>: Pixel {
    /// The new pixel type.
    type Pixel: Pixel<Subpixel=C> + 'static;
}

/// Alias to make uses of `WithChannel` less syntactically noisy.
pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Applies `f` to each subpixel of the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::map::map_subpixels;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let scaled = gray_image_i16!(
///     -2i16, -4i16;
///     -6i16, -8i16);
///
/// assert_pixels_eq!(
///     map_subpixels(&image, |x| -2 * (x as i16)),
///     scaled);
/// # }
/// ```
pub fn map_subpixels<I, P, F, S>(image: &I, f: F) -> Image<ChannelMap<P, S>>
    where I: GenericImage<Pixel=P>,
          P: WithChannel<S> + 'static,
          S: Primitive + 'static,
          F: Fn(P::Subpixel) -> S
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<ChannelMap<P, S>, Vec<S>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            let mut out_channels = out.get_pixel_mut(x, y).channels_mut();
            for c in 0..P::channel_count() {
                out_channels[c as usize]
                    = f(unsafe {*image.unsafe_get_pixel(x, y)
                        .channels().get_unchecked(c as usize) });
            }
        }
    }

    out
}

/// Applies `f` to the color of each pixel in the input image.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Rgb;
/// use imageproc::map::map_colors;
///
/// let image = gray_image!(
///     1, 2;
///     3, 4);
///
/// let rgb = rgb_image!(
///     [1, 2, 3], [2, 4, 6];
///     [3, 6, 9], [4, 8, 12]);
///
/// assert_pixels_eq!(
///     map_colors(&image, |p| { Rgb([p[0], (2 * p[0]), (3 * p[0])]) }),
///     rgb);
/// # }
/// ```
pub fn map_colors<I, P, Q, F>(image: &I, f: F) -> Image<Q>
    where I: GenericImage<Pixel=P>,
          P: Pixel,
          Q: Pixel + 'static,
          F: Fn(P) -> Q
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(pix));
            }
        }
    }

    out
}

/// Applies `f` to the colors of the pixels in the input images.
///
/// Requires `image1` and `image2` to have the same dimensions.
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::map::map_colors2;
///
/// let image1 = gray_image!(
///     1, 2,
///     3, 4
/// );
///
/// let image2 = gray_image!(
///     10, 20,
///     30, 40
/// );
///
/// let sum = gray_image!(
///     11, 22,
///     33, 44
/// );
///
/// assert_pixels_eq!(
///     map_colors2(&image1, &image2, |p, q| Luma([p[0] + q[0]])),
///     sum
/// );
/// # }
/// ```
pub fn map_colors2<I, J, P, Q, R, F>(image1: &I, image2: &J, f: F) -> Image<R>
    where I: GenericImage<Pixel=P>,
          J: GenericImage<Pixel=Q>,
          P: Pixel,
          Q: Pixel,
          R: Pixel + 'static,
          F: Fn(P, Q) -> R
{
    assert_eq!(image1.dimensions(), image2.dimensions());

    let (width, height) = image1.dimensions();
    let mut out: ImageBuffer<R, Vec<R::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let p = image1.unsafe_get_pixel(x, y);
                let q = image2.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(p, q));
            }
        }
    }

    out
}

/// Applies `f` to each pixel in the input image.
pub fn map_pixels<I, P, Q, F>(image: &I, f: F) -> Image<Q>
    where I: GenericImage<Pixel=P>,
          P: Pixel,
          Q: Pixel + 'static,
          F: Fn(u32, u32, P) -> Q
{
    let (width, height) = image.dimensions();
    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let pix = image.unsafe_get_pixel(x, y);
                out.unsafe_put_pixel(x, y, f(x, y, pix));
            }
        }
    }

    out
}

macro_rules! implement_channel_extraction {
    ($extract_name: ident, $embed_name: ident, $idx: expr) => (
        /// Create a grayscale image by extracting a channel of an RGB image.
        pub fn $extract_name<I, C>(image: &I) -> Image<Luma<C>>
            where I: GenericImage<Pixel=Rgb<C>>,
                  C: Primitive + 'static
        {
            map_colors(image, |p| Luma([p[$idx]]))
        }

        /// Create an RGB image by embedding a grayscale image in a single channel.
        pub fn $embed_name<I, C>(image: &I) -> Image<Rgb<C>>
            where I: GenericImage<Pixel=Luma<C>>,
                  C: Primitive + 'static
        {
            map_colors(image, |p| {
                let mut cs = [C::zero(); 3];
                cs[$idx] = p[0];
                Rgb(cs)
            })
        }
    )
}

implement_channel_extraction!(red_channel, as_red_channel, 0);
implement_channel_extraction!(green_channel, as_green_channel, 1);
implement_channel_extraction!(blue_channel, as_blue_channel, 2);

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

    #[test]
    fn test_map_pixels() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image_i16!(
            [1, 2, 3], [3, 5, 7];
            [4, 7, 10], [6, 10, 14]);

        let mapped = map_pixels(&image, |x, y, p| {
            let intensity = p[0] as i16;
            let offset = (x + y) as i16;
            Rgb([intensity + offset, 2 * intensity + offset, 3 * intensity + offset])
        });
        assert_pixels_eq!(mapped, expected);
    }

    #[test]
    fn test_red_channel() {
        let image = rgb_image!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let expected = gray_image!(
            1, 2;
            3, 4);

        let actual = red_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_green_channel() {
        let image = rgb_image!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let expected = gray_image!(
            2, 4;
            6, 8);

        let actual = green_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_blue_channel() {
        let image = rgb_image!(
            [1, 2, 3], [2, 4, 6];
            [3, 6, 9], [4, 8, 12]);

        let expected = gray_image!(
            3, 6;
            9, 12);

        let actual = blue_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_as_red_channel() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image!(
            [1, 0, 0], [2, 0, 0];
            [3, 0, 0], [4, 0, 0]);

        let actual = as_red_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_as_green_channel() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image!(
            [0, 1, 0], [0, 2, 0];
            [0, 3, 0], [0, 4, 0]);

        let actual = as_green_channel(&image);
        assert_pixels_eq!(actual, expected);
    }

    #[test]
    fn test_as_blue_channel() {
        let image = gray_image!(
            1, 2;
            3, 4);

        let expected = rgb_image!(
          [0, 0, 1], [0, 0, 2];
          [0, 0, 3], [0, 0, 4]);

        let actual = as_blue_channel(&image);
        assert_pixels_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>trait StrParseExt {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool;
}

impl<'a> StrParseExt for &'a str {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool,
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }
}

pub trait XmlStr {
    /// Find the end of the quoted attribute value, not including the quote
    fn end_of_attribute(&self, quote: &str) -> Option<usize>;
    /// Find the end of the direct character data
    fn end_of_char_data(&self) -> Option<usize>;
    /// Find the end of the CData section, not including the ]]>
    fn end_of_cdata(&self) -> Option<usize>;
    /// Find the end of a run of decimal characters
    fn end_of_decimal_chars(&self) -> Option<usize>;
    /// Find the end of a run of hexidecimal characters
    fn end_of_hex_chars(&self) -> Option<usize>;
    /// Find the end of the comment, not including the -->
    fn end_of_comment(&self) -> Option<usize>;
    /// Find the end of the processing instruction, not including the ?>
    fn end_of_pi_value(&self) -> Option<usize>;
    /// Find the end of the [Name](http://www.w3.org/TR/xml/#NT-Name)
    fn end_of_name(&self) -> Option<usize>;
    /// Find the end of the [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)
    fn end_of_ncname(&self) -> Option<usize>;
    /// Find the end of a run of space characters
    fn end_of_space(&self) -> Option<usize>;
    /// Find the end of the starting tag
    fn end_of_start_tag(&self) -> Option<usize>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<usize> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let quote_char = quote.chars().next().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_char_data(&self) -> Option<usize> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        let mut indices = self.char_indices();

        loop {
            let mut positions = indices.by_ref().skip_while(|&(_, c)| {
                c != '<' && c != '&' && c != ']'
            });

            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = &self[offset..];
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<usize> {
        self.find("]]>")
    }

    fn end_of_decimal_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<usize> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        self.find("--")
    }

    fn end_of_pi_value(&self) -> Option<usize> {
        self.find("?>")
    }

    fn end_of_name(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_ncname(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_ncname_start_char(), |c| c.is_ncname_char())
    }

    fn end_of_space(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<usize> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

/// Predicates used when parsing an characters in an XML document.
pub trait XmlChar {
    /// Is this a [NameStartChar](http://www.w3.org/TR/xml/#NT-NameStartChar)?
    fn is_name_start_char(self) -> bool;
    /// Is this a [NameChar](http://www.w3.org/TR/xml/#NT-NameChar)?
    fn is_name_char(self) -> bool;
    /// Does this start a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_start_char(self) -> bool;
    /// Is this a component of a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_char(self) -> bool;
    /// Is this an [XML space](http://www.w3.org/TR/xml/#NT-S)?
    fn is_space_char(self) -> bool;
    fn is_decimal_char(self) -> bool;
    fn is_hex_char(self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(self) -> bool {
        self == ':' || self.is_ncname_start_char()
    }

    fn is_name_char(self) -> bool {
        self.is_name_start_char() || self.is_ncname_char()
    }

    fn is_ncname_start_char(self) -> bool {
        match self {
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\u{0000C0}'...'\u{0000D6}' |
            '\u{0000D8}'...'\u{0000F6}' |
            '\u{0000F8}'...'\u{0002FF}' |
            '\u{000370}'...'\u{00037D}' |
            '\u{00037F}'...'\u{001FFF}' |
            '\u{00200C}'...'\u{00200D}' |
            '\u{002070}'...'\u{00218F}' |
            '\u{002C00}'...'\u{002FEF}' |
            '\u{003001}'...'\u{00D7FF}' |
            '\u{00F900}'...'\u{00FDCF}' |
            '\u{00FDF0}'...'\u{00FFFD}' |
            '\u{010000}'...'\u{0EFFFF}' => true,
            _ => false,
        }
    }

    fn is_ncname_char(self) -> bool {
        if self.is_ncname_start_char() { return true; }
        match self {
            '-'                     |
            '.'                     |
            '0'...'9'               |
            '\u{00B7}'              |
            '\u{0300}'...'\u{036F}' |
            '\u{203F}'...'\u{2040}' => true,
            _ => false
        }
    }

    fn is_space_char(self) -> bool {
        match self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(self) -> bool {
        match self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(self) -> bool {
        match self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

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

    #[test]
    fn end_of_char_data_leading_ampersand() {
        assert_eq!("&".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_less_than() {
        assert_eq!("<".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_cdata_end() {
        assert_eq!("]]>".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_until_ampersand() {
        assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_less_than() {
        assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_cdata_end() {
        assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_includes_right_square() {
        assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
    }

    #[test]
    fn end_of_char_data_includes_multiple_right_squares() {
        assert_eq!("hello]]world".end_of_char_data(), Some("hello]]world".len()));
    }
}
<commit_msg>Search for the attribute end using a char, not string<commit_after>trait StrParseExt {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool;
}

impl<'a> StrParseExt for &'a str {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool,
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }
}

pub trait XmlStr {
    /// Find the end of the quoted attribute value, not including the quote
    fn end_of_attribute(&self, quote: &str) -> Option<usize>;
    /// Find the end of the direct character data
    fn end_of_char_data(&self) -> Option<usize>;
    /// Find the end of the CData section, not including the ]]>
    fn end_of_cdata(&self) -> Option<usize>;
    /// Find the end of a run of decimal characters
    fn end_of_decimal_chars(&self) -> Option<usize>;
    /// Find the end of a run of hexidecimal characters
    fn end_of_hex_chars(&self) -> Option<usize>;
    /// Find the end of the comment, not including the -->
    fn end_of_comment(&self) -> Option<usize>;
    /// Find the end of the processing instruction, not including the ?>
    fn end_of_pi_value(&self) -> Option<usize>;
    /// Find the end of the [Name](http://www.w3.org/TR/xml/#NT-Name)
    fn end_of_name(&self) -> Option<usize>;
    /// Find the end of the [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)
    fn end_of_ncname(&self) -> Option<usize>;
    /// Find the end of a run of space characters
    fn end_of_space(&self) -> Option<usize>;
    /// Find the end of the starting tag
    fn end_of_start_tag(&self) -> Option<usize>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<usize> {
        if self.len() == 0 ||
           self.starts_with('&') ||
           self.starts_with('<') ||
           self.starts_with(quote)
        {
            return None;
        }

        let quote_char = quote.chars().next().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_char_data(&self) -> Option<usize> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        let mut indices = self.char_indices();

        loop {
            let mut positions = indices.by_ref().skip_while(|&(_, c)| {
                c != '<' && c != '&' && c != ']'
            });

            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = &self[offset..];
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<usize> {
        self.find("]]>")
    }

    fn end_of_decimal_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<usize> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        self.find("--")
    }

    fn end_of_pi_value(&self) -> Option<usize> {
        self.find("?>")
    }

    fn end_of_name(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_ncname(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_ncname_start_char(), |c| c.is_ncname_char())
    }

    fn end_of_space(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<usize> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

/// Predicates used when parsing an characters in an XML document.
pub trait XmlChar {
    /// Is this a [NameStartChar](http://www.w3.org/TR/xml/#NT-NameStartChar)?
    fn is_name_start_char(self) -> bool;
    /// Is this a [NameChar](http://www.w3.org/TR/xml/#NT-NameChar)?
    fn is_name_char(self) -> bool;
    /// Does this start a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_start_char(self) -> bool;
    /// Is this a component of a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_char(self) -> bool;
    /// Is this an [XML space](http://www.w3.org/TR/xml/#NT-S)?
    fn is_space_char(self) -> bool;
    fn is_decimal_char(self) -> bool;
    fn is_hex_char(self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(self) -> bool {
        self == ':' || self.is_ncname_start_char()
    }

    fn is_name_char(self) -> bool {
        self.is_name_start_char() || self.is_ncname_char()
    }

    fn is_ncname_start_char(self) -> bool {
        match self {
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\u{0000C0}'...'\u{0000D6}' |
            '\u{0000D8}'...'\u{0000F6}' |
            '\u{0000F8}'...'\u{0002FF}' |
            '\u{000370}'...'\u{00037D}' |
            '\u{00037F}'...'\u{001FFF}' |
            '\u{00200C}'...'\u{00200D}' |
            '\u{002070}'...'\u{00218F}' |
            '\u{002C00}'...'\u{002FEF}' |
            '\u{003001}'...'\u{00D7FF}' |
            '\u{00F900}'...'\u{00FDCF}' |
            '\u{00FDF0}'...'\u{00FFFD}' |
            '\u{010000}'...'\u{0EFFFF}' => true,
            _ => false,
        }
    }

    fn is_ncname_char(self) -> bool {
        if self.is_ncname_start_char() { return true; }
        match self {
            '-'                     |
            '.'                     |
            '0'...'9'               |
            '\u{00B7}'              |
            '\u{0300}'...'\u{036F}' |
            '\u{203F}'...'\u{2040}' => true,
            _ => false
        }
    }

    fn is_space_char(self) -> bool {
        match self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(self) -> bool {
        match self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(self) -> bool {
        match self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

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

    #[test]
    fn end_of_char_data_leading_ampersand() {
        assert_eq!("&".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_less_than() {
        assert_eq!("<".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_cdata_end() {
        assert_eq!("]]>".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_until_ampersand() {
        assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_less_than() {
        assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_cdata_end() {
        assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_includes_right_square() {
        assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
    }

    #[test]
    fn end_of_char_data_includes_multiple_right_squares() {
        assert_eq!("hello]]world".end_of_char_data(), Some("hello]]world".len()));
    }
}
<|endoftext|>


<commit_before>pub type Tag = String;
<commit_msg>Document Tag type<commit_after>/// type definition for tags
pub type Tag = String;
<|endoftext|>