<commit_before>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{:?}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Display`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test

#![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;

use std::collections::BTreeMap;
use std::str::FromStr;

pub use parser::{Parser, ParserError};

#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::encoder::{Encoder, Error, encode, encode_str};
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};

mod parser;
mod display;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod encoder;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod decoder;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug)]
#[allow(missing_docs)]
pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(String),
    Array(Array),
    Table(Table),
}

/// Type representing a TOML array, payload of the Value::Array variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the Value::Table variant
pub type Table = BTreeMap<String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::String(..), &Value::String(..)) |
            (&Value::Integer(..), &Value::Integer(..)) |
            (&Value::Float(..), &Value::Float(..)) |
            (&Value::Boolean(..), &Value::Boolean(..)) |
            (&Value::Datetime(..), &Value::Datetime(..)) |
            (&Value::Array(..), &Value::Array(..)) |
            (&Value::Table(..), &Value::Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self { Value::String(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Value::Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Value::Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Value::Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&str> {
        match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice(&self) -> Option<&[Value]> {
        match *self { Value::Array(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self { Value::Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = toml.parse().unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let ref path = match Parser::new(path).lookup() {
            Some(path) => path,
            None => return None,
        };
        let mut cur_value = self;
        if path.len() == 0 {
            return Some(cur_value)
        }

        for key in path {
            match *cur_value {
                Value::Table(ref hm) => {
                    match hm.get(key) {
                        Some(v) => cur_value = v,
                        None => return None
                    }
                },
                Value::Array(ref v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)

    }
    /// Lookups for mutable value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let mut value: toml::Value = toml.parse().unwrap();
    /// {
    ///    let string = value.lookup_mut("test.foo").unwrap();
    ///    assert_eq!(string, &mut toml::Value::String(String::from("bar")));
    ///    *string = toml::Value::String(String::from("foo"));
    /// }
    /// let result = value.lookup_mut("test.foo").unwrap();
    /// assert_eq!(result.as_str().unwrap(), "foo");
    /// ```
    pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
       let ref path = match Parser::new(path).lookup() {
            Some(path) => path,
            None => return None,
        };

        let mut cur = self;
        if path.len() == 0 {
            return Some(cur)
        }

        for key in path {
            let tmp = cur;
            match *tmp {
                Value::Table(ref mut hm) => {
                    match hm.get_mut(key) {
                        Some(v) => cur = v,
                        None => return None
                    }
                }
                Value::Array(ref mut v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur = &mut v[idx],
                        _ => return None
                    }
                }
                _ => return None
           }
        }
        Some(cur)
    }
}

impl FromStr for Value {
    type Err = Vec<ParserError>;
    fn from_str(s: &str) -> Result<Value, Vec<ParserError>> {
        let mut p = Parser::new(s);
        match p.parse().map(Value::Table) {
            Some(n) => Ok(n),
            None => Err(p.errors),
        }
    }
}

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

    #[test]
    fn lookup_mut_change() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();
        {
          let foo = value.lookup_mut("values.0.foo").unwrap();
          *foo = Value::String(String::from("bar"));
        }
        let foo = value.lookup("values.0.foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_mut_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let test_foo = value.lookup_mut("test.foo").unwrap();
            assert_eq!(test_foo.as_str().unwrap(), "bar");
        }

        {
            let foo1 = value.lookup_mut("values.1.foo").unwrap();
            assert_eq!(foo1.as_str().unwrap(), "qux");
        }

        assert!(value.lookup_mut("test.bar").is_none());
        assert!(value.lookup_mut("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_mut_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let foo = value.lookup_mut("test.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.100.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.str.foo");
            assert!(foo.is_none());
        }
    }

    #[test]
    fn lookup_mut_self() {
        let mut value: Value = r#"foo = "bar""#.parse().unwrap();

        {
            let foo = value.lookup_mut("foo").unwrap();
            assert_eq!(foo.as_str().unwrap(), "bar");
        }

        let foo = value.lookup_mut("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup_mut("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = toml.parse().unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        assert!(value.lookup("test.bar").is_none());
        assert!(value.lookup("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = toml.parse().unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }

    #[test]
    fn lookup_self() {
        let value: Value = r#"foo = "bar""#.parse().unwrap();

        let foo = value.lookup("foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");

        let foo = value.lookup("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_advanced() {
        let value: Value = "[table]\n\"value\" = 0".parse().unwrap();
        let looked = value.lookup("table.\"value\"").unwrap();
        assert_eq!(*looked, Value::Integer(0));
    }

    #[test]
    fn lookup_advanced_table() {
        let value: Value = r#"[table."name.other"] value = "my value""#.parse().unwrap();
        let looked = value.lookup(r#"table."name.other".value"#).unwrap();
        assert_eq!(*looked, Value::String(String::from("my value")));
    }

    #[test]
    fn lookup_mut_advanced() {
        let mut value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
        let looked = value.lookup_mut("table.\"value\".1").unwrap();
        assert_eq!(*looked, Value::Integer(1));
    }

}
<commit_msg>Add a bunch of negative and positive tests<commit_after>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{:?}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Display`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test

#![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;

use std::collections::BTreeMap;
use std::str::FromStr;

pub use parser::{Parser, ParserError};

#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::encoder::{Encoder, Error, encode, encode_str};
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};

mod parser;
mod display;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod encoder;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod decoder;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug)]
#[allow(missing_docs)]
pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(String),
    Array(Array),
    Table(Table),
}

/// Type representing a TOML array, payload of the Value::Array variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the Value::Table variant
pub type Table = BTreeMap<String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::String(..), &Value::String(..)) |
            (&Value::Integer(..), &Value::Integer(..)) |
            (&Value::Float(..), &Value::Float(..)) |
            (&Value::Boolean(..), &Value::Boolean(..)) |
            (&Value::Datetime(..), &Value::Datetime(..)) |
            (&Value::Array(..), &Value::Array(..)) |
            (&Value::Table(..), &Value::Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self { Value::String(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Value::Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Value::Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Value::Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&str> {
        match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice(&self) -> Option<&[Value]> {
        match *self { Value::Array(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self { Value::Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = toml.parse().unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let ref path = match Parser::new(path).lookup() {
            Some(path) => path,
            None => return None,
        };
        let mut cur_value = self;
        if path.len() == 0 {
            return Some(cur_value)
        }

        for key in path {
            match *cur_value {
                Value::Table(ref hm) => {
                    match hm.get(key) {
                        Some(v) => cur_value = v,
                        None => return None
                    }
                },
                Value::Array(ref v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)

    }
    /// Lookups for mutable value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let mut value: toml::Value = toml.parse().unwrap();
    /// {
    ///    let string = value.lookup_mut("test.foo").unwrap();
    ///    assert_eq!(string, &mut toml::Value::String(String::from("bar")));
    ///    *string = toml::Value::String(String::from("foo"));
    /// }
    /// let result = value.lookup_mut("test.foo").unwrap();
    /// assert_eq!(result.as_str().unwrap(), "foo");
    /// ```
    pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
       let ref path = match Parser::new(path).lookup() {
            Some(path) => path,
            None => return None,
        };

        let mut cur = self;
        if path.len() == 0 {
            return Some(cur)
        }

        for key in path {
            let tmp = cur;
            match *tmp {
                Value::Table(ref mut hm) => {
                    match hm.get_mut(key) {
                        Some(v) => cur = v,
                        None => return None
                    }
                }
                Value::Array(ref mut v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur = &mut v[idx],
                        _ => return None
                    }
                }
                _ => return None
           }
        }
        Some(cur)
    }
}

impl FromStr for Value {
    type Err = Vec<ParserError>;
    fn from_str(s: &str) -> Result<Value, Vec<ParserError>> {
        let mut p = Parser::new(s);
        match p.parse().map(Value::Table) {
            Some(n) => Ok(n),
            None => Err(p.errors),
        }
    }
}

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

    #[test]
    fn lookup_mut_change() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();
        {
          let foo = value.lookup_mut("values.0.foo").unwrap();
          *foo = Value::String(String::from("bar"));
        }
        let foo = value.lookup("values.0.foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_mut_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let test_foo = value.lookup_mut("test.foo").unwrap();
            assert_eq!(test_foo.as_str().unwrap(), "bar");
        }

        {
            let foo1 = value.lookup_mut("values.1.foo").unwrap();
            assert_eq!(foo1.as_str().unwrap(), "qux");
        }

        assert!(value.lookup_mut("test.bar").is_none());
        assert!(value.lookup_mut("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_mut_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let foo = value.lookup_mut("test.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.100.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.str.foo");
            assert!(foo.is_none());
        }
    }

    #[test]
    fn lookup_mut_self() {
        let mut value: Value = r#"foo = "bar""#.parse().unwrap();

        {
            let foo = value.lookup_mut("foo").unwrap();
            assert_eq!(foo.as_str().unwrap(), "bar");
        }

        let foo = value.lookup_mut("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup_mut("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = toml.parse().unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        assert!(value.lookup("test.bar").is_none());
        assert!(value.lookup("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = toml.parse().unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }

    #[test]
    fn lookup_self() {
        let value: Value = r#"foo = "bar""#.parse().unwrap();

        let foo = value.lookup("foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");

        let foo = value.lookup("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_advanced() {
        let value: Value = "[table]\n\"value\" = 0".parse().unwrap();
        let looked = value.lookup("table.\"value\"").unwrap();
        assert_eq!(*looked, Value::Integer(0));
    }

    #[test]
    fn lookup_advanced_table() {
        let value: Value = r#"[table."name.other"] value = "my value""#.parse().unwrap();
        let looked = value.lookup(r#"table."name.other".value"#).unwrap();
        assert_eq!(*looked, Value::String(String::from("my value")));
    }

    #[test]
    fn lookup_mut_advanced() {
        let mut value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
        let looked = value.lookup_mut("table.\"value\".1").unwrap();
        assert_eq!(*looked, Value::Integer(1));
    }

    #[test]
    fn single_dot() {
        let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
        assert_eq!(None, value.lookup("."));
    }

    #[test]
    fn array_dot() {
        let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
        assert_eq!(None, value.lookup("0."));
    }

    #[test]
    fn dot_inside() {
        let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
        assert_eq!(None, value.lookup("table.\"value.0\""));
    }

    #[test]
    fn table_with_quotes() {
        let value: Value = "[table.\"element\"]\n\"value\" = [0, 1, 2]".parse().unwrap();
        assert_eq!(None, value.lookup("\"table.element\".\"value\".0"));
    }

    #[test]
    fn table_with_quotes_2() {
        let value: Value = "[table.\"element\"]\n\"value\" = [0, 1, 2]".parse().unwrap();
        assert_eq!(Value::Integer(0), *value.lookup("table.\"element\".\"value\".0").unwrap());
    }

}
<|endoftext|>


<commit_before>pub mod integer;
pub mod nil;

pub struct Parse {
    plugins: Vec<Plugin>,
}

impl Parse {
    pub fn parse(&self, s: &str) -> Box<SExpr> {
        println!("TODO!");
        Box::new(nil::Nil)
    }

    pub fn add_plugin_mut(&self, p: Plugin) -> Parse {
        self = self.add_plugin(p);
        self
    }

    pub fn add_plugin(&self, p: Plugin) -> Parse {
        println!("TODO!");
    }

    pub fn remove_plugin_mut(&self, p: Plugin) -> Parse {
        self = self.remove_plugin(p);
        self
    }

    pub fn remove_plugin(&self, p: Plugin) -> Parse {
        println!("TODO!");
    }

    pub fn default_plugins() -> Parse {
        Parse {
            plugins: vec![] // Put defaults here
        }
    }
}

pub trait PluginData {} // something should go here that we can access..

pub trait Plugin { // is this needed besides AtomParser? Are there any other plugin types?
    fn handle_this(&self, &str) -> bool;
    fn handle(&self, &str) -> PluginData;
}

pub trait AtomParser {
    fn str_is(&self, &str) -> bool;
    fn parse_str(&self, &str) -> AtomData;
}

impl Plugin for AtomParser {
    fn handle_this(&self, s: &str) -> bool {
        self.str_is(s)
    }
    fn handle(&self, s: &str) -> AtomData {
        self.parse_str(s)
    }
}

pub trait SExpr : PartialEq {}

struct Cons {
    first: SExpr,
    second: SExpr,
}

pub trait AtomData {
    type T : PartialEq;
    fn get_value(&self) -> Self::T;
}

impl PartialEq for Cons {
    fn eq(&self, other: Cons) -> bool {
        self.first == other.first && self.second == other.second
    }
}

impl PartialEq for AtomData {
    fn eq(&self, other: AtomData) {
        self.get_value() == other.get_value()
    }
}

impl<T: SExpr> SExpr for Cons {}

impl<T: AtomData> SExpr for T {}
<commit_msg>Reduce errors, 1 error type left<commit_after>pub mod integer;
pub mod nil;

pub struct Parse {
    plugins: Vec<Plugin>,
}

impl Parse {
    pub fn parse(&self, s: &str) -> Box<SExpr> {
        println!("TODO!");
        Box::new(nil::Nil)
    }

    pub fn add_plugin_mut(&mut self, p: Plugin) -> Parse {
        self = self.add_plugin(p);
        self
    }

    pub fn add_plugin(&self, p: Plugin) -> Parse {
        println!("TODO!");
    }

    pub fn remove_plugin_mut(&mut self, p: Plugin) -> Parse {
        self = self.remove_plugin(p);
        self
    }

    pub fn remove_plugin(&self, p: Plugin) -> Parse {
        println!("TODO!");
    }

    pub fn default_plugins() -> Parse {
        Parse {
            plugins: vec![integer::IntegerParser] // Put defaults here
        }
    }
}

pub trait PluginData {} // something should go here that we can access..

pub trait Plugin { // is this needed besides AtomParser? Are there any other plugin types?
    fn handle_this(&self, &str) -> bool;
    fn handle(&self, &str) -> PluginData;
}

pub trait AtomParser {
    fn str_is(&self, &str) -> bool;
    fn parse_str<T>(&self, &str) -> AtomData<T=T>;
}

impl Plugin for AtomParser {
    fn handle_this(&self, s: &str) -> bool {
        self.str_is(s)
    }
    fn handle<T>(&self, s: &str) -> AtomData<T=T> {
        self.parse_str(s)
    }
}

pub trait SExpr : PartialEq {}

struct Cons {
    first: SExpr,
    second: SExpr,
}

pub trait AtomData {
    type T : PartialEq;
    fn get_value(&self) -> Self::T;
}

impl PartialEq for Cons {
    fn eq(&self, other: Cons) -> bool {
        self.first == other.first && self.second == other.second
    }
}

impl<T> PartialEq for AtomData<T=T> {
    fn eq(&self, other: AtomData<T=T>) {
        self.get_value() == other.get_value()
    }
}

impl SExpr for Cons {}

impl<T: AtomData> SExpr for T {}
<|endoftext|>


<commit_before>extern crate rand;
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
#[cfg(any(target_os = "macos", target_os = "ios"))] extern crate mach_o_sys;
#[cfg(all(unix, test))] extern crate nix;

mod alloc;

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

// -- memcmp --

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

// -- memset / memzero --

/// General memset.
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    let s = s as *mut u8;
    let c = c as u8;

    for i in 0..n as isize {
        ::std::ptr::write_volatile(s.offset(i), c);
    }
}

/// Call memset_s.
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    use mach_o_sys::ranlib;

    extern {
        fn memset_s(s: *mut libc::c_void, smax: ranlib::rsize_t, c: libc::c_int, n: ranlib::rsize_t) -> ranlib::errno_t;
    }

    if n > 0 {
        let ret = memset_s(s as *mut libc::c_void, n as ranlib::rsize_t, c, n as ranlib::rsize_t);

        if (ret != 0) {
            panic!("memset_s return with error value {}", ret);
        }
    }
}

/// General memzero.
#[cfg(not(any(windows, target_os = "freebsd", target_os = "openbsd")))]
#[inline]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    memset(dest, 0, n);
}

/// Call explicit_bzero.
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    extern {
        fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
    }
    explicit_bzero(dest as *mut libc::c_void, n);
}

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

// -- mlock / munlock --

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

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

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

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

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

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

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

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

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

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

// -- mprotect --

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

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

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

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

/// Windows VirtualProtect.
#[cfg(windows)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    let mut old = std::mem::uninitialized();
    kernel32::VirtualProtect(
        ptr as winapi::LPVOID,
        len as winapi::SIZE_T,
        prot as winapi::DWORD,
        &mut old as winapi::PDWORD
    ) != 0
}
<commit_msg>fix: memcmp/memset never inline<commit_after>extern crate rand;
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
#[cfg(any(target_os = "macos", target_os = "ios"))] extern crate mach_o_sys;
#[cfg(all(unix, test))] extern crate nix;

mod alloc;

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

// -- memcmp --

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

// -- memset / memzero --

/// General memset.
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
#[inline(never)]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    let s = s as *mut u8;
    let c = c as u8;

    for i in 0..n as isize {
        ::std::ptr::write_volatile(s.offset(i), c);
    }
}

/// Call memset_s.
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    use mach_o_sys::ranlib;

    extern {
        fn memset_s(s: *mut libc::c_void, smax: ranlib::rsize_t, c: libc::c_int, n: ranlib::rsize_t) -> ranlib::errno_t;
    }

    if n > 0 {
        let ret = memset_s(s as *mut libc::c_void, n as ranlib::rsize_t, c, n as ranlib::rsize_t);

        if (ret != 0) {
            panic!("memset_s return with error value {}", ret);
        }
    }
}

/// General memzero.
#[cfg(not(any(windows, target_os = "freebsd", target_os = "openbsd")))]
#[inline]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    memset(dest, 0, n);
}

/// Call explicit_bzero.
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    extern {
        fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
    }
    explicit_bzero(dest as *mut libc::c_void, n);
}

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

// -- mlock / munlock --

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

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

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

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

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

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

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

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

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

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

// -- mprotect --

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

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

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

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

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


<commit_before>extern crate itertools;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::rc::Rc;

use itertools::Itertools;

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write(self.id.as_bytes());
    }
}

impl PartialEq<Document> for Document {
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Rc<Document>,
    pub highlighted: (usize, usize),
}

/// An Index is anything that can store Documents and return matching Documents for a query.
trait Index {
    /// Given a Document, stores it in the index.
    fn index(&mut self, doc: Document);
    /// Given a query, return the set of Documents that match the query.
    /// What constitutes a "match" is implementation-specific; loosely, a Document should
    /// match a query if they are somehow related. A naive implementation might simply
    /// return the set of Documents for which `query` is a substring of their content.
    fn search(&self, query: &str) -> HashSet<SearchResult>;
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
type InvertedIndex = BTreeMap<String, HashSet<IndexedDocument>>;

impl Index for InvertedIndex {
    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    fn index(&mut self, doc: Document) {
        let doc = Rc::new(doc);
        let analyzed = doc.content()
            .char_indices()
            .group_by(|&(_, c)| c.is_whitespace())
            .filter(|&(is_whitespace, _)| !is_whitespace)
            .flat_map(|(_, chars)| (1..chars.len() + 1).map(move |to| {
                let word: String = chars[..to].iter().map(|&(_, c)| c).collect();
                let start = chars[0].0;
                let (last_idx, last_char) = chars[to - 1];
                let finish = last_idx + last_char.len_utf8();
                (word, (start, finish))
            }));

        for (ngram, highlighted) in analyzed {
            self.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: highlighted });
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    fn search(&self, query: &str) -> HashSet<SearchResult> {
        let map = query.split_whitespace()
            .flat_map(|word| self.get(word))
            .flat_map(|docs| docs)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        map.into_iter()
            .map(|(doc, mut highlights)| {
                highlights.sort();
                SearchResult { doc: doc, highlights: highlights }
            })
        .collect()
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct SearchResult {
    doc: Rc<Document>,
    highlights: Vec<(usize, usize)>,
}

impl SearchResult {
    #[cfg(test)]
    fn new(doc: Rc<Document>, highlights: Vec<(usize, usize)>) -> SearchResult {
        SearchResult {
            doc: doc,
            highlights: highlights,
        }
    }

    pub fn doc(&self) -> &Rc<Document> {
        &self.doc
    }

    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    pub fn highlighted_content(&self) -> String {
        let &SearchResult {ref doc, ref highlights} = self;
        let content = doc.content();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &(begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("today");
    let expected = [
        SearchResult::new(Rc::new(doc1), vec![(25, 30)]),
        SearchResult::new(Rc::new(doc2), vec![(13, 18)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());
}

#[test]
fn test_ngrams() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Rc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Rc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Rc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Rc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!(expected[0].highlighted_content(), "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc.clone());
    let to_search = "å";
    let search_results = index.search(to_search);
    let &SearchResult { ref doc, ref highlights } = search_results.iter().next().unwrap();
    let (begin, end) = highlights[0];
    assert_eq!(&doc.content()[begin..end], to_search);
}
<commit_msg>Make trait/type public<commit_after>extern crate itertools;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::rc::Rc;

use itertools::Itertools;

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write(self.id.as_bytes());
    }
}

impl PartialEq<Document> for Document {
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Rc<Document>,
    pub highlighted: (usize, usize),
}

/// An Index is anything that can store Documents and return matching Documents for a query.
pub trait Index {
    /// Given a Document, stores it in the index.
    fn index(&mut self, doc: Document);
    /// Given a query, return the set of Documents that match the query.
    /// What constitutes a "match" is implementation-specific; loosely, a Document should
    /// match a query if they are somehow related. A naive implementation might simply
    /// return the set of Documents for which `query` is a substring of their content.
    fn search(&self, query: &str) -> HashSet<SearchResult>;
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
pub type InvertedIndex = BTreeMap<String, HashSet<IndexedDocument>>;

impl Index for InvertedIndex {
    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    fn index(&mut self, doc: Document) {
        let doc = Rc::new(doc);
        let analyzed = doc.content()
            .char_indices()
            .group_by(|&(_, c)| c.is_whitespace())
            .filter(|&(is_whitespace, _)| !is_whitespace)
            .flat_map(|(_, chars)| (1..chars.len() + 1).map(move |to| {
                let word: String = chars[..to].iter().map(|&(_, c)| c).collect();
                let start = chars[0].0;
                let (last_idx, last_char) = chars[to - 1];
                let finish = last_idx + last_char.len_utf8();
                (word, (start, finish))
            }));

        for (ngram, highlighted) in analyzed {
            self.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: highlighted });
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    fn search(&self, query: &str) -> HashSet<SearchResult> {
        let map = query.split_whitespace()
            .flat_map(|word| self.get(word))
            .flat_map(|docs| docs)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        map.into_iter()
            .map(|(doc, mut highlights)| {
                highlights.sort();
                SearchResult { doc: doc, highlights: highlights }
            })
        .collect()
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct SearchResult {
    doc: Rc<Document>,
    highlights: Vec<(usize, usize)>,
}

impl SearchResult {
    #[cfg(test)]
    fn new(doc: Rc<Document>, highlights: Vec<(usize, usize)>) -> SearchResult {
        SearchResult {
            doc: doc,
            highlights: highlights,
        }
    }

    pub fn doc(&self) -> &Rc<Document> {
        &self.doc
    }

    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    pub fn highlighted_content(&self) -> String {
        let &SearchResult {ref doc, ref highlights} = self;
        let content = doc.content();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &(begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("today");
    let expected = [
        SearchResult::new(Rc::new(doc1), vec![(25, 30)]),
        SearchResult::new(Rc::new(doc2), vec![(13, 18)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());
}

#[test]
fn test_ngrams() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Rc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Rc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Rc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Rc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!(expected[0].highlighted_content(), "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc.clone());
    let to_search = "å";
    let search_results = index.search(to_search);
    let &SearchResult { ref doc, ref highlights } = search_results.iter().next().unwrap();
    let (begin, end) = highlights[0];
    assert_eq!(&doc.content()[begin..end], to_search);
}
<|endoftext|>


<commit_before>//! Quasi-quoting without a Syntex dependency, intended for use with [Macros
//! 1.1](https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md).
//!
//! ```toml
//! [dependencies]
//! quote = "0.3"
//! ```
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//! #
//! # fn main() {}
//! ```
//!
//! Interpolation is done with `#var`:
//!
//! ```
//! let tokens = quote! {
//!     struct SerializeWith #generics #where_clause {
//!         value: &'a #field_ty,
//!         phantom: ::std::marker::PhantomData<#item_ty>,
//!     }
//!
//!     impl #generics serde::Serialize for SerializeWith #generics #where_clause {
//!         fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
//!             where S: serde::Serializer
//!         {
//!             #path(self.value, s)
//!         }
//!     }
//!
//!     SerializeWith {
//!         value: #value,
//!         phantom: ::std::marker::PhantomData::<#item_ty>,
//!     }
//! };
//! ```
//!
//! Repetition is done using `#(...)*` or `#(...),*` very similar to `macro_rules!`:
//!
//! - `#(#var)*` - no separators
//! - `#(#var),*` - the character before the asterisk is used as a separator
//! - `#( struct #var; )*` - the repetition can contain other things
//! - `#( #k => println!("{}", #v), )*` - even multiple interpolations
//!
//! The return type of `quote!` is `quote::Tokens`. Tokens can be interpolated into
//! other quotes:
//!
//! ```text
//! let t = quote! { /* ... */ };
//! return quote! { /* ... */ #t /* ... */ };
//! ```
//!
//! Call `to_string()` or `as_str()` on a Tokens to get a `String` or `&str` of Rust
//! code.
//!
//! The `quote!` macro relies on deep recursion so some large invocations may fail
//! with "recursion limit reached" when you compile. If it fails, bump up the
//! recursion limit by adding `#![recursion_limit = "128"]` to your crate. An even
//! higher limit may be necessary for especially large invocations.

extern crate proc_macro2;
extern crate proc_macro;

mod tokens;
pub use tokens::Tokens;

mod to_tokens;
pub use to_tokens::{ByteStr, ToTokens};

// Not public API.
#[doc(hidden)]
pub mod __rt {
    // Not public API.
    pub use proc_macro2::*;

    // Not public API.
    pub fn parse(tokens: &mut ::Tokens, span: Span, s: &str) {
        let s: TokenStream = s.parse().expect("invalid token stream");
        tokens.append_all(s.into_iter().map(|mut t| {
            t.span = span;
            t
        }));
    }

    // Not public API.
    pub fn append_kind(tokens: &mut ::Tokens, span: Span, kind: TokenNode) {
        tokens.append(TokenTree {
            span: span,
            kind: kind,
        })
    }
}

/// The whole point.
#[macro_export]
macro_rules! quote {
    ($($tt:tt)*) => (quote_spanned!($crate::__rt::Span::default(), $($tt)*));
}

/// Same as `quote!` above, but all generated tokens will use the span provided
#[macro_export]
macro_rules! quote_spanned {
    ($span:expr, $($tt:tt)*) => {
        {
            let mut _s = $crate::Tokens::new();
            let _span = $span;
            quote_each_token!(_s _span $($tt)*);
            _s
        }
    };
}

// Extract the names of all #metavariables and pass them to the $finish macro.
//
// in:   pounded_var_names!(then () a #b c #( #d )* #e)
// out:  then!(() b d e)
#[macro_export]
#[doc(hidden)]
macro_rules! pounded_var_names {
    ($finish:ident ($($found:ident)*) # ( $($inner:tt)* ) $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) # [ $($inner:tt)* ] $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) # { $($inner:tt)* } $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) # $first:ident $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)* $first) $($rest)*)
    };

    ($finish:ident ($($found:ident)*) ( $($inner:tt)* ) $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) [ $($inner:tt)* ] $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) { $($inner:tt)* } $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) $ignore:tt $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($rest)*)
    };

    ($finish:ident ($($found:ident)*)) => {
        $finish!(() $($found)*)
    };
}

// in:   nested_tuples_pat!(() a b c d e)
// out:  ((((a b) c) d) e)
//
// in:   nested_tuples_pat!(() a)
// out:  a
#[macro_export]
#[doc(hidden)]
macro_rules! nested_tuples_pat {
    (()) => {
        &()
    };

    (() $first:ident $($rest:ident)*) => {
        nested_tuples_pat!(($first) $($rest)*)
    };

    (($pat:pat) $first:ident $($rest:ident)*) => {
        nested_tuples_pat!((($pat, $first)) $($rest)*)
    };

    (($done:pat)) => {
        $done
    };
}

// in:   multi_zip_expr!(() a b c d e)
// out:  a.into_iter().zip(b).zip(c).zip(d).zip(e)
//
// in:   multi_zip_iter!(() a)
// out:  a
#[macro_export]
#[doc(hidden)]
macro_rules! multi_zip_expr {
    (()) => {
        &[]
    };

    (() $single:ident) => {
        $single
    };

    (() $first:ident $($rest:ident)*) => {
        multi_zip_expr!(($first.into_iter()) $($rest)*)
    };

    (($zips:expr) $first:ident $($rest:ident)*) => {
        multi_zip_expr!(($zips.zip($first)) $($rest)*)
    };

    (($done:expr)) => {
        $done
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! quote_each_token {
    ($tokens:ident $span:ident) => {};

    ($tokens:ident $span:ident # ! $($rest:tt)*) => {
        quote_each_token!($tokens $span #);
        quote_each_token!($tokens $span !);
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # ( $($inner:tt)* ) * $($rest:tt)*) => {
        for pounded_var_names!(nested_tuples_pat () $($inner)*)
        in pounded_var_names!(multi_zip_expr () $($inner)*) {
            quote_each_token!($tokens $span $($inner)*);
        }
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt * $($rest:tt)*) => {
        for (_i, pounded_var_names!(nested_tuples_pat () $($inner)*))
        in pounded_var_names!(multi_zip_expr () $($inner)*).into_iter().enumerate() {
            if _i > 0 {
                quote_each_token!($tokens $span $sep);
            }
            quote_each_token!($tokens $span $($inner)*);
        }
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # [ $($inner:tt)* ] $($rest:tt)*) => {
        quote_each_token!($tokens $span #);
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Bracket,
                quote_spanned! { $span, $($inner)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # $first:ident $($rest:tt)*) => {
        $crate::ToTokens::to_tokens(&$first, &mut $tokens);
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident ( $($first:tt)* ) $($rest:tt)*) => {
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Parenthesis,
                quote_spanned! { $span, $($first)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident [ $($first:tt)* ] $($rest:tt)*) => {
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Bracket,
                quote_spanned! { $span, $($first)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident { $($first:tt)* } $($rest:tt)*) => {
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Brace,
                quote_spanned! { $span, $($first)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident $first:tt $($rest:tt)*) => {
        // TODO: this seems slow... special case some `:tt` arguments?
        $crate::__rt::parse(&mut $tokens, $span, stringify!($first));
        quote_each_token!($tokens $span $($rest)*);
    };
}
<commit_msg>Make the realistic example compile<commit_after>//! Quasi-quoting without a Syntex dependency, intended for use with [Macros
//! 1.1](https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md).
//!
//! ```toml
//! [dependencies]
//! quote = "0.3"
//! ```
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//! #
//! # fn main() {}
//! ```
//!
//! Interpolation is done with `#var`:
//!
//! ```
//! # #[macro_use]
//! # extern crate quote;
//! #
//! # fn main() {
//! #     let generics = "";
//! #     let where_clause = "";
//! #     let field_ty = "";
//! #     let item_ty = "";
//! #     let path = "";
//! #     let value = "";
//! #
//! let tokens = quote! {
//!     struct SerializeWith #generics #where_clause {
//!         value: &'a #field_ty,
//!         phantom: ::std::marker::PhantomData<#item_ty>,
//!     }
//!
//!     impl #generics serde::Serialize for SerializeWith #generics #where_clause {
//!         fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
//!             where S: serde::Serializer
//!         {
//!             #path(self.value, s)
//!         }
//!     }
//!
//!     SerializeWith {
//!         value: #value,
//!         phantom: ::std::marker::PhantomData::<#item_ty>,
//!     }
//! };
//! #
//! # }
//! ```
//!
//! Repetition is done using `#(...)*` or `#(...),*` very similar to `macro_rules!`:
//!
//! - `#(#var)*` - no separators
//! - `#(#var),*` - the character before the asterisk is used as a separator
//! - `#( struct #var; )*` - the repetition can contain other things
//! - `#( #k => println!("{}", #v), )*` - even multiple interpolations
//!
//! The return type of `quote!` is `quote::Tokens`. Tokens can be interpolated into
//! other quotes:
//!
//! ```text
//! let t = quote! { /* ... */ };
//! return quote! { /* ... */ #t /* ... */ };
//! ```
//!
//! Call `to_string()` or `as_str()` on a Tokens to get a `String` or `&str` of Rust
//! code.
//!
//! The `quote!` macro relies on deep recursion so some large invocations may fail
//! with "recursion limit reached" when you compile. If it fails, bump up the
//! recursion limit by adding `#![recursion_limit = "128"]` to your crate. An even
//! higher limit may be necessary for especially large invocations.

extern crate proc_macro2;
extern crate proc_macro;

mod tokens;
pub use tokens::Tokens;

mod to_tokens;
pub use to_tokens::{ByteStr, ToTokens};

// Not public API.
#[doc(hidden)]
pub mod __rt {
    // Not public API.
    pub use proc_macro2::*;

    // Not public API.
    pub fn parse(tokens: &mut ::Tokens, span: Span, s: &str) {
        let s: TokenStream = s.parse().expect("invalid token stream");
        tokens.append_all(s.into_iter().map(|mut t| {
            t.span = span;
            t
        }));
    }

    // Not public API.
    pub fn append_kind(tokens: &mut ::Tokens, span: Span, kind: TokenNode) {
        tokens.append(TokenTree {
            span: span,
            kind: kind,
        })
    }
}

/// The whole point.
#[macro_export]
macro_rules! quote {
    ($($tt:tt)*) => (quote_spanned!($crate::__rt::Span::default(), $($tt)*));
}

/// Same as `quote!` above, but all generated tokens will use the span provided
#[macro_export]
macro_rules! quote_spanned {
    ($span:expr, $($tt:tt)*) => {
        {
            let mut _s = $crate::Tokens::new();
            let _span = $span;
            quote_each_token!(_s _span $($tt)*);
            _s
        }
    };
}

// Extract the names of all #metavariables and pass them to the $finish macro.
//
// in:   pounded_var_names!(then () a #b c #( #d )* #e)
// out:  then!(() b d e)
#[macro_export]
#[doc(hidden)]
macro_rules! pounded_var_names {
    ($finish:ident ($($found:ident)*) # ( $($inner:tt)* ) $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) # [ $($inner:tt)* ] $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) # { $($inner:tt)* } $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) # $first:ident $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)* $first) $($rest)*)
    };

    ($finish:ident ($($found:ident)*) ( $($inner:tt)* ) $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) [ $($inner:tt)* ] $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) { $($inner:tt)* } $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
    };

    ($finish:ident ($($found:ident)*) $ignore:tt $($rest:tt)*) => {
        pounded_var_names!($finish ($($found)*) $($rest)*)
    };

    ($finish:ident ($($found:ident)*)) => {
        $finish!(() $($found)*)
    };
}

// in:   nested_tuples_pat!(() a b c d e)
// out:  ((((a b) c) d) e)
//
// in:   nested_tuples_pat!(() a)
// out:  a
#[macro_export]
#[doc(hidden)]
macro_rules! nested_tuples_pat {
    (()) => {
        &()
    };

    (() $first:ident $($rest:ident)*) => {
        nested_tuples_pat!(($first) $($rest)*)
    };

    (($pat:pat) $first:ident $($rest:ident)*) => {
        nested_tuples_pat!((($pat, $first)) $($rest)*)
    };

    (($done:pat)) => {
        $done
    };
}

// in:   multi_zip_expr!(() a b c d e)
// out:  a.into_iter().zip(b).zip(c).zip(d).zip(e)
//
// in:   multi_zip_iter!(() a)
// out:  a
#[macro_export]
#[doc(hidden)]
macro_rules! multi_zip_expr {
    (()) => {
        &[]
    };

    (() $single:ident) => {
        $single
    };

    (() $first:ident $($rest:ident)*) => {
        multi_zip_expr!(($first.into_iter()) $($rest)*)
    };

    (($zips:expr) $first:ident $($rest:ident)*) => {
        multi_zip_expr!(($zips.zip($first)) $($rest)*)
    };

    (($done:expr)) => {
        $done
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! quote_each_token {
    ($tokens:ident $span:ident) => {};

    ($tokens:ident $span:ident # ! $($rest:tt)*) => {
        quote_each_token!($tokens $span #);
        quote_each_token!($tokens $span !);
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # ( $($inner:tt)* ) * $($rest:tt)*) => {
        for pounded_var_names!(nested_tuples_pat () $($inner)*)
        in pounded_var_names!(multi_zip_expr () $($inner)*) {
            quote_each_token!($tokens $span $($inner)*);
        }
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt * $($rest:tt)*) => {
        for (_i, pounded_var_names!(nested_tuples_pat () $($inner)*))
        in pounded_var_names!(multi_zip_expr () $($inner)*).into_iter().enumerate() {
            if _i > 0 {
                quote_each_token!($tokens $span $sep);
            }
            quote_each_token!($tokens $span $($inner)*);
        }
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # [ $($inner:tt)* ] $($rest:tt)*) => {
        quote_each_token!($tokens $span #);
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Bracket,
                quote_spanned! { $span, $($inner)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident # $first:ident $($rest:tt)*) => {
        $crate::ToTokens::to_tokens(&$first, &mut $tokens);
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident ( $($first:tt)* ) $($rest:tt)*) => {
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Parenthesis,
                quote_spanned! { $span, $($first)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident [ $($first:tt)* ] $($rest:tt)*) => {
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Bracket,
                quote_spanned! { $span, $($first)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident { $($first:tt)* } $($rest:tt)*) => {
        $crate::__rt::append_kind(&mut $tokens,
            $span,
            $crate::__rt::TokenNode::Group(
                $crate::__rt::Delimiter::Brace,
                quote_spanned! { $span, $($first)* }.into()
            ));
        quote_each_token!($tokens $span $($rest)*);
    };

    ($tokens:ident $span:ident $first:tt $($rest:tt)*) => {
        // TODO: this seems slow... special case some `:tt` arguments?
        $crate::__rt::parse(&mut $tokens, $span, stringify!($first));
        quote_each_token!($tokens $span $($rest)*);
    };
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::collections::HashSet;

/// A graph is represeted by as a weighted
/// [Adjenceny matrix](http://en.wikipedia.org/wiki/Adjacency_matrix)
pub struct Graph {
  /// The underlaying graph represented here with weights as an i32 (should
  /// probably be generic) the graph is represented as an
  /// [Adjenceny matrix](http://en.wikipedia.org/wiki/Adjacency_matrix) of
  /// Optionals, where None indicates that there doesn't exist a vertex and
  /// Some<i32> indicates that There is a vertex of weight i32.
  graph: Vec<Vec<Option<i32>>>
}
impl Graph {
  /// `new` allows for initializing the graph struct with a given adjecency matrix
  ///
  /// ## Arguments
  /// * `input` - an adjecency matrix in made out of a two-dimensional `Vec` of
  ///    weights. Weights are represented as `i32`:s and can thus be positive or
  ///    negative numbers.
  ///
  /// ## Example
  /// ```ignore
  ///  let rawgraph = vec![vec![Some(0), Some(20), Some(80), Some(50),     None,     None],
  ///                      vec![   None,  Some(0),     None,     None,     None,     None],
  ///                      vec![   None,     None,  Some(0),     None,     None,     None],
  ///                      vec![   None,     None,     None,  Some(0), Some(50),     None],
  ///                      vec![   None,     None, Some(20),     None,  Some(0), Some(50)],
  ///                      vec![   None,     None,     None,     None,     None,  Some(0)]];
  /// let g = Graph::new(rawgraph);
  /// ```
  pub fn new(input: Vec<Vec<Option<i32>>>) -> Graph { Graph { graph: input } }

  /*
  1  procedure BFS(G,v) is
  2      let Q be a queue
  3      Q.push(v)
  4      label v as discovered
  5      while Q is not empty
  6         v ← Q.pop()
  7         for all edges from v to w in G.adjacentEdges(v) do
  8             if w is not labeled as discovered
  9                 Q.push(w)
  10                label w as discovered
  */
  /// `breadth_first_search` implements breadth first search from `start` to the
  /// `target` and returns the path found as a `VecDeque<usize>` of nodes. This
  /// is an optional type as there might not be a path.
  ///
  /// **NOTE** as this is breadth first search this search ignores any assigned
  /// weight to nodes.
  ///
  /// ## Arguments
  /// * `start`  - an `usize` designating the start node, or row in the adjecency matrix
  /// * `target` - an `usize` designating the target node, or row in the adjecency matrix
  ///
  /// ## Returns
  /// Either the found path between start and target as a `VecDeque` of `usize`:s
  /// or `None` if there is no path.
  pub fn breadth_first_search(&self, start: usize, target: usize) -> Option<VecDeque<usize>> {
    let mut q: VecDeque<usize> = VecDeque::new();
    let mut discovered: HashSet<usize> = HashSet::new();
    let mut prev: Vec<usize> = Vec::with_capacity(self.graph.len());
    let mut pathfound = false;
    for _ in (0..self.graph.len()) { prev.push(0); }

    q.push_back(start);
    discovered.insert(start);
    //println!("q size: {} and is empty: {}", q.len(), q.is_empty());

    while !q.is_empty() {
      let v = q.pop_front();
      match v {
        None => {}, // q is empty
        Some(v) => { // we are working on a new layer, branch the queue?
         // println!("Checking out: {}", v);
          if !discovered.contains(&v) {
            //println!("{:?} does not contain: {}", discovered, v);
            discovered.insert(v);
          }
          if v == target {
            //println!("Target located: q:{:?}, disco: {:?}, prev: {:?}", q, discovered, prev);
            pathfound = true;
          }
          for i in (0..self.graph[v].len()) {
            match self.graph[v][i] {
              None => {}, // no vertex between v and i
              Some(_) => {
                //println!("  A vertex between: {} and {} exists. q: {:?}, disco: {:?}", v, i, q, discovered);
                if !discovered.contains(&i) {
                  q.push_back(i);
                  prev[i]=v; //track prev (v) on i
                }
              }
            }
          }
        }
      }
    }
    if pathfound {
      let mut path: VecDeque<usize> = VecDeque::new();
      let mut curr = target;
      // backtrack over the prev array to construc the path
      while curr != start {
        path.push_front(curr);
        curr = prev[curr];
      }
      path.push_front(start);
      return Some(path)
    }
    return None
  }
}

#[test]
fn breadth_first_search_test() {
  let testgraph = vec![vec![Some(0), Some(20), Some(80), Some(50),     None,     None, None],
                       vec![   None,  Some(0),     None,     None,     None,     None, None],
                       vec![   None,     None,  Some(0),     None,     None,     None,  Some(50)],
                       vec![   None,     None,     None,  Some(0), Some(50),     None, None],
                       vec![   None,     None, Some(20),     None,  Some(0), Some(50),  Some(40)],
                       vec![   None,     None,     None,     None,     None,  Some(0), None],
                       vec![   None,     None,     None,     None,     None,     None, Some(0)]];
  let start: usize = 0;
  let target: usize = 6;
  let g = Graph::new(testgraph);
  let res = g.breadth_first_search(start, target);
  //assert_eq!(res.is_none(), false);
  match res {
    None => {
      println!("bfs search returned None");
      assert!(false);
    }
    Some(result) => {
      println!("Bfs returned something: {:?}", result);
      assert_eq!(result[result.len()-1], target);
      assert_eq!(result[0], start);
      //assert!(false);
    }
  }
}

#[test]
fn breadth_first_search_test_no_valid_path() {
  let testgraph = vec![vec![Some(0), Some(20), Some(80), Some(50),     None,     None, None],
                       vec![   None,  Some(0),     None,     None,     None,     None, None],
                       vec![   None,     None,  Some(0),     None,     None,     None,  Some(50)],
                       vec![   None,     None,     None,  Some(0), Some(50),     None, None],
                       vec![   None,     None, Some(20),     None,  Some(0),     None,  Some(40)],
                       vec![   None,     None,     None,     None,     None,  Some(0), None],
                       vec![   None,     None,     None,     None,     None,     None, Some(0)]];
  let start: usize = 0;
  let target: usize = 5; // There is no valid path between 0 and 5
  let g = Graph::new(testgraph);
  let res = g.breadth_first_search(start, target);

  // The expected return value is None
  match res {
    None => {
      println!("bfs search returned None");
      assert!(true);
    }
    Some(result) => {
      println!("Bfs returned something: {:?}", result);
      assert_eq!(result[result.len()-1], target);
      assert_eq!(result[0], start);
      assert!(false);
    }
  }
}
<commit_msg>Cleaned up some comments, no functional changes<commit_after>use std::collections::VecDeque;
use std::collections::HashSet;

/// A graph is represeted by as a weighted
/// [Adjenceny matrix](http://en.wikipedia.org/wiki/Adjacency_matrix)
pub struct Graph {
  /// The underlaying graph represented here with weights as an i32 (should
  /// probably be generic) the graph is represented as an
  /// [Adjenceny matrix](http://en.wikipedia.org/wiki/Adjacency_matrix) of
  /// Optionals, where None indicates that there doesn't exist a vertex and
  /// Some<i32> indicates that There is a vertex of weight i32.
  graph: Vec<Vec<Option<i32>>>
}
impl Graph {
  /// `new` allows for initializing the graph struct with a given adjecency matrix
  ///
  /// ## Arguments
  /// * `input` - an adjecency matrix in made out of a two-dimensional `Vec` of
  ///    weights. Weights are represented as `i32`:s and can thus be positive or
  ///    negative numbers.
  ///
  /// ## Example
  /// ```ignore
  ///  let rawgraph = vec![vec![Some(0), Some(20), Some(80), Some(50),     None,     None],
  ///                      vec![   None,  Some(0),     None,     None,     None,     None],
  ///                      vec![   None,     None,  Some(0),     None,     None,     None],
  ///                      vec![   None,     None,     None,  Some(0), Some(50),     None],
  ///                      vec![   None,     None, Some(20),     None,  Some(0), Some(50)],
  ///                      vec![   None,     None,     None,     None,     None,  Some(0)]];
  /// let g = Graph::new(rawgraph);
  /// ```
  pub fn new(input: Vec<Vec<Option<i32>>>) -> Graph { Graph { graph: input } }

  /*
  1  procedure BFS(G,v) is
  2      let Q be a queue
  3      Q.push(v)
  4      label v as discovered
  5      while Q is not empty
  6         v ← Q.pop()
  7         for all edges from v to w in G.adjacentEdges(v) do
  8             if w is not labeled as discovered
  9                 Q.push(w)
  10                label w as discovered
  */
  /// `breadth_first_search` implements breadth first search from `start` to the
  /// `target` and returns the path found as a `VecDeque<usize>` of nodes. This
  /// is an optional type as there might not be a path.
  ///
  /// **NOTE** as this is breadth first search this search ignores any assigned
  /// weight to nodes.
  ///
  /// ## Arguments
  /// * `start`  - an `usize` designating the start node, or row in the adjecency matrix
  /// * `target` - an `usize` designating the target node, or row in the adjecency matrix
  ///
  /// ## Returns
  /// Either the found path between start and target as a `VecDeque` of `usize`:s
  /// or `None` if there is no path.
  pub fn breadth_first_search(&self, start: usize, target: usize) -> Option<VecDeque<usize>> {
    let mut q: VecDeque<usize> = VecDeque::new();
    let mut discovered: HashSet<usize> = HashSet::new();
    let mut prev: Vec<usize> = Vec::with_capacity(self.graph.len());
    let mut pathfound = false;
    for _ in (0..self.graph.len()) { prev.push(0); }

    q.push_back(start);
    discovered.insert(start);

    while !q.is_empty() {
      let v = q.pop_front();
      match v {
        None => {}, // q is empty
        Some(v) => { // we are working on a new layer, branch the queue?
          if !discovered.contains(&v) {
            discovered.insert(v);
          }
          if v == target {
            pathfound = true;
          }
          for i in (0..self.graph[v].len()) {
            match self.graph[v][i] {
              None => {}, // no vertex between v and i
              Some(_) => {
                if !discovered.contains(&i) {
                  q.push_back(i);
                  prev[i]=v; //track prev (v) on i
                }
              }
            }
          }
        }
      }
    }
    if pathfound {
      let mut path: VecDeque<usize> = VecDeque::new();
      let mut curr = target;
      // backtrack over the prev array to construct the path
      while curr != start {
        path.push_front(curr);
        curr = prev[curr];
      }
      path.push_front(start);
      return Some(path)
    }
    return None
  }
}

#[test]
fn breadth_first_search_test() {
  let testgraph = vec![vec![Some(0), Some(20), Some(80), Some(50),     None,     None, None],
                       vec![   None,  Some(0),     None,     None,     None,     None, None],
                       vec![   None,     None,  Some(0),     None,     None,     None,  Some(50)],
                       vec![   None,     None,     None,  Some(0), Some(50),     None, None],
                       vec![   None,     None, Some(20),     None,  Some(0), Some(50),  Some(40)],
                       vec![   None,     None,     None,     None,     None,  Some(0), None],
                       vec![   None,     None,     None,     None,     None,     None, Some(0)]];
  let start: usize = 0;
  let target: usize = 6;
  let g = Graph::new(testgraph);
  let res = g.breadth_first_search(start, target);
  match res {
    None => {
      println!("bfs search returned None");
      assert!(false);
    }
    Some(result) => {
      println!("Bfs returned something: {:?}", result);
      assert_eq!(result[result.len()-1], target);
      assert_eq!(result[0], start);
    }
  }
}

#[test]
fn breadth_first_search_test_no_valid_path() {
  let testgraph = vec![vec![Some(0), Some(20), Some(80), Some(50),     None,     None, None],
                       vec![   None,  Some(0),     None,     None,     None,     None, None],
                       vec![   None,     None,  Some(0),     None,     None,     None,  Some(50)],
                       vec![   None,     None,     None,  Some(0), Some(50),     None, None],
                       vec![   None,     None, Some(20),     None,  Some(0),     None,  Some(40)],
                       vec![   None,     None,     None,     None,     None,  Some(0), None],
                       vec![   None,     None,     None,     None,     None,     None, Some(0)]];
  let start: usize = 0;
  let target: usize = 5; // There is no valid path between 0 and 5
  let g = Graph::new(testgraph);
  let res = g.breadth_first_search(start, target);

  // The expected return value is None
  match res {
    None => {
      println!("bfs search returned None");
      assert!(true);
    }
    Some(result) => {
      println!("Bfs returned something: {:?}", result);
      assert_eq!(result[result.len()-1], target);
      assert_eq!(result[0], start);
      assert!(false);
    }
  }
}
<|endoftext|>


<commit_before>//! Set breakpoints from within the comfort of your editor.
//!
//! ## Usage
//!
//! Import the macros from the `breakpoint` crate. Unfortunately, the
//! `breakpoint!()` macro relies on the `asm!()` macro, so we need
//! `#![feature(asm)]` as well.
//!
//! ```rust
//! #![feature(asm)]
//! #[macro_use] extern crate breakpoint;
//! # fn main() { }
//! ```
//!
//! Then, anywhere you would like to pause at in your debugger, add the
//! following line:
//!
//! ```rust
//! # #![feature(asm)]
//! # #[macro_use] extern crate breakpoint;
//! # fn main() {
//! # if false {
//! // Always pause.
//! breakpoint!();
//! # }
//!
//! // Only pause if `condition` is true.
//! # let condition = false;
//! breakpoint!(condition);
//! # }
//! ```
//!
//! ## Example
//!
//! Imagine we have this really tricky function that needs to be debugged,
//! because we are seeing integer underflows:
//!
//! ```rust
//! fn tricky_function_must_be_debugged(val: usize) -> usize {
//!     val - 1
//! }
//! ```
//!
//! We can set a breakpoint in the program from the comfort of our editor,
//! rebuild, and run under a debugger to see where things are going wrong:
//!
//! ```rust
//! # #![feature(asm)]
//! # #[macro_use] extern crate breakpoint;
//! # fn main() { }
//!
//! fn tricky_function_must_be_debugged(val: usize) -> usize {
//!     // Set a breakpoint before the underflow, so we can debug!
//!     breakpoint!();
//!     val - 1
//! }
//! ```
//!
//! If the  problematic function is  only called  a handful of  times, congrats!
//! You've uncovered the root cause of the bug by now!
//!
//! If, however, the tricky function is called many times, and the bug only
//! manifests after many calls, it is useful to break only if some condition
//! evaluates to true:
//!
//! ```rust
//! # #![feature(asm)]
//! # #[macro_use] extern crate breakpoint;
//! # fn main() { }
//!
//! fn tricky_function_must_be_debugged(val: usize) -> usize {
//!     // Only break if we are going to underflow!
//!     breakpoint!(val == 0);
//!     val - 1
//! }
//! ```
//!
//! ## Why?
//!
//! It can be convenient. Especially when you're already in your editor, you
//! can't remember your debugger's incantation for conditional breakpoints
//! (often made worse by poor support for parsing Rust expressions in current
//! versions of debuggers), and/or your crate isn't super big so rebuilding is
//! fast.
//!
//! In particular, I got annoyed that panics from failing tests didn't
//! automatically pause my debugger, and could never remember the incantation
//! for breaking on panic off the top of my head. I find this easier than that,
//! most of the time.
//!
//! Admittedly, `breakpoint!()` is far from perfect. These things tend to work
//! better in dynamic languages where re-evaluating a function is super easy and
//! doesn't need a full recompilation.

#![deny(missing_docs)]
#![feature(asm)]

extern crate libc;

#[macro_export]

/// Set a breakpoint.
///
/// See the [module-level documentation](./index.html).
macro_rules! breakpoint {
    () => {
        unsafe {
            asm!("int3"::);
            // For whatever reason, debuggers will show the paused line as the
            // next one after the int3, so we have this dummy line here for
            // ergonomics.
            let _ = 1;
        }
    };
    ($e:expr) => {
        if $e {
            breakpoint!();
        }
    };
}

#[doc(hidden)]
pub mod tests {
    use std::cell::Cell;
    use libc::types::os::arch::c95::c_int;

    thread_local!(static HIT_BREAKPOINT : Cell<bool> = Cell::new(false));

    #[repr(C)]
    type sig_t = extern "C" fn(c_int);

    extern "C" {
        fn signal(sig: c_int, func: sig_t) -> sig_t;
    }

    static SIGTRAP : c_int = 5;

    extern "C" fn sigtrap_handler(sig: c_int) {
        assert_eq!(sig, SIGTRAP);
        HIT_BREAKPOINT.with(|v| v.set(true));
    }

    pub fn reset() {
        HIT_BREAKPOINT.with(|v| v.set(false));
        unsafe {
            signal(SIGTRAP, sigtrap_handler);
        }
    }

    pub fn hit_breakpoint() -> bool {
        HIT_BREAKPOINT.with(|v| v.get())
    }

    #[test]
    fn test_that_we_can_use_the_breakpoint_macro() {
        reset();
        breakpoint!();
        assert_eq!(hit_breakpoint(), true);
    }

    #[test]
    fn test_condition() {
        reset();

        let x = 0;

        breakpoint!(x == 1);
        assert_eq!(hit_breakpoint(), false);

        breakpoint!(x == 0);
        assert_eq!(hit_breakpoint(), true);
    }
}
<commit_msg>And also point to the intrinsic from the docs<commit_after>//! Set breakpoints from within the comfort of your editor.
//!
//! [YOU MAY WANT TO USE THIS INSTEAD](http://doc.rust-lang.org/std/intrinsics/fn.breakpoint.html)
//!
//! ## Usage
//!
//! Import the macros from the `breakpoint` crate. Unfortunately, the
//! `breakpoint!()` macro relies on the `asm!()` macro, so we need
//! `#![feature(asm)]` as well.
//!
//! ```rust
//! #![feature(asm)]
//! #[macro_use] extern crate breakpoint;
//! # fn main() { }
//! ```
//!
//! Then, anywhere you would like to pause at in your debugger, add the
//! following line:
//!
//! ```rust
//! # #![feature(asm)]
//! # #[macro_use] extern crate breakpoint;
//! # fn main() {
//! # if false {
//! // Always pause.
//! breakpoint!();
//! # }
//!
//! // Only pause if `condition` is true.
//! # let condition = false;
//! breakpoint!(condition);
//! # }
//! ```
//!
//! ## Example
//!
//! Imagine we have this really tricky function that needs to be debugged,
//! because we are seeing integer underflows:
//!
//! ```rust
//! fn tricky_function_must_be_debugged(val: usize) -> usize {
//!     val - 1
//! }
//! ```
//!
//! We can set a breakpoint in the program from the comfort of our editor,
//! rebuild, and run under a debugger to see where things are going wrong:
//!
//! ```rust
//! # #![feature(asm)]
//! # #[macro_use] extern crate breakpoint;
//! # fn main() { }
//!
//! fn tricky_function_must_be_debugged(val: usize) -> usize {
//!     // Set a breakpoint before the underflow, so we can debug!
//!     breakpoint!();
//!     val - 1
//! }
//! ```
//!
//! If the  problematic function is  only called  a handful of  times, congrats!
//! You've uncovered the root cause of the bug by now!
//!
//! If, however, the tricky function is called many times, and the bug only
//! manifests after many calls, it is useful to break only if some condition
//! evaluates to true:
//!
//! ```rust
//! # #![feature(asm)]
//! # #[macro_use] extern crate breakpoint;
//! # fn main() { }
//!
//! fn tricky_function_must_be_debugged(val: usize) -> usize {
//!     // Only break if we are going to underflow!
//!     breakpoint!(val == 0);
//!     val - 1
//! }
//! ```
//!
//! ## Why?
//!
//! It can be convenient. Especially when you're already in your editor, you
//! can't remember your debugger's incantation for conditional breakpoints
//! (often made worse by poor support for parsing Rust expressions in current
//! versions of debuggers), and/or your crate isn't super big so rebuilding is
//! fast.
//!
//! In particular, I got annoyed that panics from failing tests didn't
//! automatically pause my debugger, and could never remember the incantation
//! for breaking on panic off the top of my head. I find this easier than that,
//! most of the time.
//!
//! Admittedly, `breakpoint!()` is far from perfect. These things tend to work
//! better in dynamic languages where re-evaluating a function is super easy and
//! doesn't need a full recompilation.

#![deny(missing_docs)]
#![feature(asm)]

extern crate libc;

#[macro_export]

/// Set a breakpoint.
///
/// See the [module-level documentation](./index.html).
macro_rules! breakpoint {
    () => {
        unsafe {
            asm!("int3"::);
            // For whatever reason, debuggers will show the paused line as the
            // next one after the int3, so we have this dummy line here for
            // ergonomics.
            let _ = 1;
        }
    };
    ($e:expr) => {
        if $e {
            breakpoint!();
        }
    };
}

#[doc(hidden)]
pub mod tests {
    use std::cell::Cell;
    use libc::types::os::arch::c95::c_int;

    thread_local!(static HIT_BREAKPOINT : Cell<bool> = Cell::new(false));

    #[repr(C)]
    type sig_t = extern "C" fn(c_int);

    extern "C" {
        fn signal(sig: c_int, func: sig_t) -> sig_t;
    }

    static SIGTRAP : c_int = 5;

    extern "C" fn sigtrap_handler(sig: c_int) {
        assert_eq!(sig, SIGTRAP);
        HIT_BREAKPOINT.with(|v| v.set(true));
    }

    pub fn reset() {
        HIT_BREAKPOINT.with(|v| v.set(false));
        unsafe {
            signal(SIGTRAP, sigtrap_handler);
        }
    }

    pub fn hit_breakpoint() -> bool {
        HIT_BREAKPOINT.with(|v| v.get())
    }

    #[test]
    fn test_that_we_can_use_the_breakpoint_macro() {
        reset();
        breakpoint!();
        assert_eq!(hit_breakpoint(), true);
    }

    #[test]
    fn test_condition() {
        reset();

        let x = 0;

        breakpoint!(x == 1);
        assert_eq!(hit_breakpoint(), false);

        breakpoint!(x == 0);
        assert_eq!(hit_breakpoint(), true);
    }
}
<|endoftext|>