<commit_before>use into::IntoError;

#[macro_export]
macro_rules! generate_error_imports {
    () => {
        use std::error::Error;
        use std::fmt::Error as FmtError;
        use std::fmt::{Display, Formatter};

        use $crate::into::IntoError;
    }
}

#[macro_export]
macro_rules! generate_error_module {
    ( $exprs:item ) => {
        pub mod error {
            generate_error_imports!();
            $exprs
        }
    }
}

#[macro_export]
macro_rules! generate_custom_error_types {
    {
        $name: ident,
        $kindname: ident,
        $customMemberTypeName: ident,
        $($kind:ident => $string:expr),*
    } => {
        #[derive(Clone, Copy, Debug, PartialEq)]
        pub enum $kindname {
            $( $kind ),*
        }

        impl Display for $kindname {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                let s = match *self {
                    $( $kindname::$kind => $string ),*
                };
                try!(write!(fmt, "{}", s));
                Ok(())
            }

        }

        impl IntoError for $kindname {
            type Target = $name;

            fn into_error(self) -> Self::Target {
                $name::new(self, None)
            }

            fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
                $name::new(self, Some(cause))
            }

        }

        #[derive(Debug)]
        pub struct $name {
            err_type: $kindname,
            cause: Option<Box<Error>>,
            custom_data: Option<$customMemberTypeName>,
        }

        impl $name {

            pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
                $name {
                    err_type: errtype,
                    cause: cause,
                    custom_data: None,
                }
            }

            pub fn err_type(&self) -> $kindname {
                self.err_type
            }

        }

        impl Into<$name> for $kindname {

            fn into(self) -> $name {
                $name::new(self, None)
            }

        }

        impl Display for $name {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                try!(write!(fmt, "[{}]", self.err_type));
                Ok(())
            }

        }

        impl Error for $name {

            fn description(&self) -> &str {
                match self.err_type {
                    $( $kindname::$kind => $string ),*
                }
            }

            fn cause(&self) -> Option<&Error> {
                self.cause.as_ref().map(|e| &**e)
            }

        }

    }
}

#[macro_export]
macro_rules! generate_error_types {
    (
        $name: ident,
        $kindname: ident,
        $($kind:ident => $string:expr),*
    ) => {
        #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
        pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
        generate_custom_error_types!($name, $kindname,
                                     SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
                                     $($kind => $string),*);
    }
}

#[cfg(test)]
mod test {

    generate_error_module!(
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    );

    #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
    pub struct CustomData {
        pub test: i32,
        pub othr: i64,
    }

    generate_error_imports!();

    generate_custom_error_types!(CustomTestError, CustomTestErrorKind,
        CustomData,
        CustomErrorKindA => "customerrorkind a",
        CustomErrorKindB => "customerrorkind B");

    impl CustomTestError {
        pub fn test(&self) -> i32 {
            match self.custom_data {
                Some(t) => t.test,
                None => 0,
            }
        }

        pub fn bar(&self) -> i64 {
            match self.custom_data {
                Some(t) => t.othr,
                None => 0,
            }
        }
    }

    #[test]
    fn test_a() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_b() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_ab() {
        use std::error::Error;
        use self::error::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    pub mod anothererrormod {
        generate_error_imports!();
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    }

    #[test]
    fn test_other_a() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_other_b() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_other_ab() {
        use std::error::Error;
        use self::anothererrormod::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }
}
<commit_msg>Add result helper<commit_after>use into::IntoError;

#[macro_export]
macro_rules! generate_error_imports {
    () => {
        use std::error::Error;
        use std::fmt::Error as FmtError;
        use std::fmt::{Display, Formatter};

        use $crate::into::IntoError;
    }
}

#[macro_export]
macro_rules! generate_error_module {
    ( $exprs:item ) => {
        pub mod error {
            generate_error_imports!();
            $exprs
        }
    }
}

#[macro_export]
macro_rules! generate_custom_error_types {
    {
        $name: ident,
        $kindname: ident,
        $customMemberTypeName: ident,
        $($kind:ident => $string:expr),*
    } => {
        #[derive(Clone, Copy, Debug, PartialEq)]
        pub enum $kindname {
            $( $kind ),*
        }

        impl Display for $kindname {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                let s = match *self {
                    $( $kindname::$kind => $string ),*
                };
                try!(write!(fmt, "{}", s));
                Ok(())
            }

        }

        impl IntoError for $kindname {
            type Target = $name;

            fn into_error(self) -> Self::Target {
                $name::new(self, None)
            }

            fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
                $name::new(self, Some(cause))
            }

        }

        #[derive(Debug)]
        pub struct $name {
            err_type: $kindname,
            cause: Option<Box<Error>>,
            custom_data: Option<$customMemberTypeName>,
        }

        impl $name {

            pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
                $name {
                    err_type: errtype,
                    cause: cause,
                    custom_data: None,
                }
            }

            pub fn err_type(&self) -> $kindname {
                self.err_type
            }

        }

        impl Into<$name> for $kindname {

            fn into(self) -> $name {
                $name::new(self, None)
            }

        }

        impl Display for $name {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                try!(write!(fmt, "[{}]", self.err_type));
                Ok(())
            }

        }

        impl Error for $name {

            fn description(&self) -> &str {
                match self.err_type {
                    $( $kindname::$kind => $string ),*
                }
            }

            fn cause(&self) -> Option<&Error> {
                self.cause.as_ref().map(|e| &**e)
            }

        }

    }
}

#[macro_export]
macro_rules! generate_result_helper {
    (
        $name: ident,
        $kindname: ident
    ) => {
        /// Trait to replace
        ///
        /// ```ignore
        /// foo.map_err(Box::new).map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(e))
        /// // or:
        /// foo.map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(Box::new(e)))
        /// ```
        ///
        /// with much nicer
        ///
        /// ```ignore
        /// foo.map_err_into(SomeType::SomeErrorKind)
        /// ```
        ///
        pub trait MapErrInto<T> {
            fn map_err_into(self, error_kind: $kindname) -> Result<T, $name>;
        }

        impl<T, E: Error + 'static> MapErrInto<T> for Result<T, E> {

            fn map_err_into(self, error_kind: $kindname) -> Result<T, $name> {
                self.map_err(Box::new)
                    .map_err(|e| error_kind.into_error_with_cause(e))
            }

        }
    }
}

#[macro_export]
macro_rules! generate_error_types {
    (
        $name: ident,
        $kindname: ident,
        $($kind:ident => $string:expr),*
    ) => {
        #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
        pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
        generate_custom_error_types!($name, $kindname,
                                     SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
                                     $($kind => $string),*);

        generate_result_helper!($name, $kindname);
    }
}

#[cfg(test)]
mod test {

    generate_error_module!(
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    );

    #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
    pub struct CustomData {
        pub test: i32,
        pub othr: i64,
    }

    generate_error_imports!();

    generate_custom_error_types!(CustomTestError, CustomTestErrorKind,
        CustomData,
        CustomErrorKindA => "customerrorkind a",
        CustomErrorKindB => "customerrorkind B");

    impl CustomTestError {
        pub fn test(&self) -> i32 {
            match self.custom_data {
                Some(t) => t.test,
                None => 0,
            }
        }

        pub fn bar(&self) -> i64 {
            match self.custom_data {
                Some(t) => t.othr,
                None => 0,
            }
        }
    }

    #[test]
    fn test_a() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_b() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_ab() {
        use std::error::Error;
        use self::error::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    pub mod anothererrormod {
        generate_error_imports!();
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    }

    #[test]
    fn test_other_a() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_other_b() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_other_ab() {
        use std::error::Error;
        use self::anothererrormod::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }
}
<|endoftext|>


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

#![feature(slice_patterns)]

enum t { a, b, }

fn main() {
    let x = t::a;
    match x { t::b => { } } //~ ERROR non-exhaustive patterns: `a` not covered
    match true { //~ ERROR non-exhaustive patterns: `false` not covered
      true => {}
    }
    match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
      None => {}
    }
    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, _)` not covered
      (_, _, 4) => {}
    }
    match (t::a, t::a) { //~ ERROR non-exhaustive patterns: `(a, a)` not covered
      (t::a, t::b) => {}
      (t::b, t::a) => {}
    }
    match t::a { //~ ERROR non-exhaustive patterns: `b` not covered
      t::a => {}
    }
    // This is exhaustive, though the algorithm got it wrong at one point
    match (t::a, t::b) {
      (t::a, _) => {}
      (_, t::a) => {}
      (t::b, t::b) => {}
    }
    let vec = vec![Some(42), None, Some(21)];
    let vec: &[Option<isize>] = &vec;
    match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
        [Some(..), None, ref tail..] => {}
        [Some(..), Some(..), ref tail..] => {}
        [None] => {}
    }
    let vec = vec![1];
    let vec: &[isize] = &vec;
    match *vec {
        [_, ref tail..] => (),
        [] => ()
    }
    let vec = vec![0.5f32];
    let vec: &[f32] = &vec;
    match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
        [0.1, 0.2, 0.3] => (),
        [0.1, 0.2] => (),
        [0.1] => (),
        [] => ()
    }
    let vec = vec![Some(42), None, Some(21)];
    let vec: &[Option<isize>] = &vec;
    match *vec {
        [Some(..), None, ref tail..] => {}
        [Some(..), Some(..), ref tail..] => {}
        [None, None, ref tail..] => {}
        [None, Some(..), ref tail..] => {}
        [Some(_)] => {}
        [None] => {}
        [] => {}
    }
}
<commit_msg>Fix non exhaustive match test<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(slice_patterns)]
#![allow(illegal_floating_point_literal_pattern)]

enum t { a, b, }

fn main() {
    let x = t::a;
    match x { t::b => { } } //~ ERROR non-exhaustive patterns: `a` not covered
    match true { //~ ERROR non-exhaustive patterns: `false` not covered
      true => {}
    }
    match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
      None => {}
    }
    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, _)` not covered
      (_, _, 4) => {}
    }
    match (t::a, t::a) { //~ ERROR non-exhaustive patterns: `(a, a)` not covered
      (t::a, t::b) => {}
      (t::b, t::a) => {}
    }
    match t::a { //~ ERROR non-exhaustive patterns: `b` not covered
      t::a => {}
    }
    // This is exhaustive, though the algorithm got it wrong at one point
    match (t::a, t::b) {
      (t::a, _) => {}
      (_, t::a) => {}
      (t::b, t::b) => {}
    }
    let vec = vec![Some(42), None, Some(21)];
    let vec: &[Option<isize>] = &vec;
    match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
        [Some(..), None, ref tail..] => {}
        [Some(..), Some(..), ref tail..] => {}
        [None] => {}
    }
    let vec = vec![1];
    let vec: &[isize] = &vec;
    match *vec {
        [_, ref tail..] => (),
        [] => ()
    }
    let vec = vec![0.5f32];
    let vec: &[f32] = &vec;
    match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
        [0.1, 0.2, 0.3] => (),
        [0.1, 0.2] => (),
        [0.1] => (),
        [] => ()
    }
    let vec = vec![Some(42), None, Some(21)];
    let vec: &[Option<isize>] = &vec;
    match *vec {
        [Some(..), None, ref tail..] => {}
        [Some(..), Some(..), ref tail..] => {}
        [None, None, ref tail..] => {}
        [None, Some(..), ref tail..] => {}
        [Some(_)] => {}
        [None] => {}
        [] => {}
    }
}
<|endoftext|>


<commit_before>use story_builder::article_provider::*;
use std::borrow::Borrow;

pub struct StoryBuilder<'a> {
    article_provider: &'a ArticleProvider,
    max_depth: u8,
}

impl <'a> StoryBuilder<'a>  {
    pub fn new(article_provider: &'a ArticleProvider) -> StoryBuilder<'a> {
        StoryBuilder {
            article_provider,
            max_depth: 5, // default value for now
        }
    }

    fn build_story(&self, start_topic: &str , end_topic: &str) -> Result<String, String> {
                   // If one of the topics is an empty string, do not try to make a story out of it.
        if start_topic == "" {
            return Err("Missing start topic.".to_owned());
        }
        if end_topic == "" {
            return Err("Missing end topic.".to_owned());
        }

                   // If both topics are the same,
                   // there is no point in trying to figure out the story.
        if start_topic == end_topic {
            return Err("No story to build; same start and end topics.".to_owned());
        }

                   // Load the first article
        let start_article = match self.article_provider.get(start_topic) {
            Some(start_article) => start_article,
            None => {return Err(self.build_suggestions_msg(start_topic));},
        };

                   // Load the end article
        let end_article = match self.article_provider.get(end_topic) {
            Some(end_topic) => end_topic,
            None => {return Err(self.build_suggestions_msg(end_topic));},
        };

                   /* To build a story, we need to build a tree starting at the start_article
                      node and going down in a "breadth-first" way; that way, once we find
                      the end note, we know it is the shortest path to it. Also, going depth-first
                      will be impossibly long to complete sincethe depth of the wikipedia
                      article tree is almost infinite. */

                   // Initialize the last level vector with the start article:
        let last_level = vec![start_article];
                   /* We look for a paragraph that holds a reference to our end topic
                      somewhere in the last level we fetched: */
        for article in last_level.iter() {
            if let Some(text) = StoryBuilder::find_text_for_topic_in_article(article.borrow(), end_topic) {
                // Found the topic. Format and return.
                return Ok(format!("{}\r\n", text));
            }
        }

        Err(format!("Reached depth of <{}> without finding <{}>. Stopping search.", self.max_depth, end_topic).to_owned())
    }

    fn build_suggestions_msg(&self, topic: &str) -> String {
        let mut msg = String::from(format!("Cannot find wikipedia article for <{}>, try one of the following suggestions:\r\n", topic));
        for sugg in self.article_provider.search(topic) {
        msg.push_str(&format!("- {}\r\n", &sugg));
        }

        msg
    }

    fn find_text_for_topic_in_article<'b>(article: &'b Article, topic: &str) -> Option<&'b str> {
        if let Some(paragraph) = article.get_paragraphs().iter().find(|par| {
                   // if any of the topics in the paragraph is <end>, return it.
            par.topics.iter().any(|t| {t == topic})
            }) {
                   // We found the paragraph; return it directly.
            return Some(&paragraph.text);
        } else {
            None
        }
    }
}

struct TreeNode<T> {
    data: T,
}

impl <T> TreeNode<T> {
    fn new(data: T) -> TreeNode<T> {
        TreeNode {
            data
        }
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Added code to expand one level of story search<commit_after>use story_builder::article_provider::*;
use std::borrow::Borrow;

pub struct StoryBuilder<'a> {
    article_provider: &'a ArticleProvider,
    max_depth: u8,
}

impl <'a> StoryBuilder<'a>  {
    pub fn new(article_provider: &'a ArticleProvider) -> StoryBuilder<'a> {
        StoryBuilder {
            article_provider,
            max_depth: 5, // default value for now
        }
    }

    fn build_story(&self, start_topic: &str , end_topic: &str) -> Result<String, String> {
                   // If one of the topics is an empty string, do not try to make a story out of it.
        if start_topic == "" {
            return Err("Missing start topic.".to_owned());
        }
        if end_topic == "" {
            return Err("Missing end topic.".to_owned());
        }

                   // If both topics are the same,
                   // there is no point in trying to figure out the story.
        if start_topic == end_topic {
            return Err("No story to build; same start and end topics.".to_owned());
        }

                   // Load the first article
        let start_article = match self.article_provider.get(start_topic) {
            Some(start_article) => start_article,
            None => {return Err(self.build_suggestions_msg(start_topic));},
        };

                   // Load the end article
        let end_article = match self.article_provider.get(end_topic) {
            Some(end_topic) => end_topic,
            None => {return Err(self.build_suggestions_msg(end_topic));},
        };

                   /* To build a story, we need to build a tree starting at the start_article
                      node and going down in a "breadth-first" way; that way, once we find
                      the end note, we know it is the shortest path to it. Also, going depth-first
                      will be impossibly long to complete sincethe depth of the wikipedia
                      article tree is almost infinite. */

                   // Initialize the last level vector with the start article:
        let last_level = vec![start_article];
                   /* We look for a paragraph that holds a reference to our end topic
                      somewhere in the last level we fetched: */
        for article in last_level.iter() {
            if let Some(text) = StoryBuilder::find_text_for_topic_in_article(article.borrow(), end_topic) {
                // Found the topic. Format and return.
                return Ok(format!("{}\r\n", text));
            }
        }
                   // Then, if we did not find anything, we go down one more level:
       let last_level: Vec<Box<Article>> = last_level.iter().flat_map(|article| {
                   /* Iterate on each paragraph of this article, then map on it to
                      get the article for each related topic in it. */
           article.get_paragraphs().iter().flat_map(|paragraph| {
               paragraph.topics.iter().map(|topic| -> Box<Article> {
                   self.article_provider.get(topic).unwrap()
                   })
               })
           }).collect();

        Err(format!("Reached depth of <{}> without finding <{}>. Stopping search.", self.max_depth, end_topic).to_owned())
    }

    fn build_suggestions_msg(&self, topic: &str) -> String {
        let mut msg = String::from(format!("Cannot find wikipedia article for <{}>, try one of the following suggestions:\r\n", topic));
        for sugg in self.article_provider.search(topic) {
        msg.push_str(&format!("- {}\r\n", &sugg));
        }

        msg
    }

    fn find_text_for_topic_in_article<'b>(article: &'b Article, topic: &str) -> Option<&'b str> {
        if let Some(paragraph) = article.get_paragraphs().iter().find(|par| {
                   // if any of the topics in the paragraph is <end>, return it.
            par.topics.iter().any(|t| {t == topic})
            }) {
                   // We found the paragraph; return it directly.
            return Some(&paragraph.text);
        } else {
            None
        }
    }
}

struct TreeNode<T> {
    data: T,
}

impl <T> TreeNode<T> {
    fn new(data: T) -> TreeNode<T> {
        TreeNode {
            data
        }
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use std::fmt::{Debug, Formatter};
use std::fmt;
use std::ops::Deref;

use clap::ArgMatches;

use runtime::Runtime;
use module::Module;

use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::create_tag_filter;
use module::helpers::cli::create_hash_filter;
use module::helpers::cli::create_text_header_field_grep_filter;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt
                         .store()
                         .new_file_with_header(self, header);

        let result = self.rt
            .store()
            .load(self, &parser, &fileid)
            .map(|file| {
                info!("{}", Yellow.paint(format!("Created file in memory: {}", fileid)));
                self.rt
                    .store()
                    .persist(&parser, file)
            })
            .unwrap_or(false);

        if result {
            info!("{}", Red.paint("Adding worked"));
        } else {
            info!("{}", Green.paint("Adding failed"));
        }

        result
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter))
        };

        let files  = self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file));
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files,
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: open
     */
    fn command_open(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Red};
        use open;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            Box::new(hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter)))
        };
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can open now: {:?}", file);
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url| {
                    if open::that(&url[..]).is_ok() {
                        info!("{}", Green.paint(format!("open({})", url)));
                        true
                    } else {
                        info!("{}", Red.paint(format!("could not open({})", url)));
                        false
                    }
                })
                .unwrap_or(false)
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (succ, fail) = result;
        info!("{}", Green.paint(format!("open() succeeded for {} files", succ)));
        info!("{}", Red.paint(format!(  "open() failed    for {} files", fail)));
        return fail == 0;
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        let parser = Parser::new(JsonHeaderParser::new(None));

        let filter = {
            let hash_filter = create_hash_filter(matches, "id", false);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", false);
            let tags_filter = create_tag_filter(matches, "tags", false);
            hash_filter.or(Box::new(text_filter)).or(Box::new(tags_filter))
        };

        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (worked, failed) = result;

        info!("{}", Green.paint(format!("Removing succeeded for {} files", worked)));
        info!("{}", Red.paint(format!(  "Removing failed for {} files", failed)));

        return failed == 0;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            cli_tags.clone()
        }, rebuild_header_with_tags)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("open") => {
                self.command_open(matches.subcommand_matches("open").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("{}", Red.bold().paint("No command given, doing nothing"));
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }

    fn runtime(&self) -> &Runtime {
        self.rt
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "BM"));
        Ok(())
    }

}

<commit_msg>Remove unused import<commit_after>use std::fmt::{Debug, Formatter};
use std::fmt;
use std::ops::Deref;

use clap::ArgMatches;

use runtime::Runtime;
use module::Module;

use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::create_tag_filter;
use module::helpers::cli::create_hash_filter;
use module::helpers::cli::create_text_header_field_grep_filter;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt
                         .store()
                         .new_file_with_header(self, header);

        let result = self.rt
            .store()
            .load(self, &parser, &fileid)
            .map(|file| {
                info!("{}", Yellow.paint(format!("Created file in memory: {}", fileid)));
                self.rt
                    .store()
                    .persist(&parser, file)
            })
            .unwrap_or(false);

        if result {
            info!("{}", Red.paint("Adding worked"));
        } else {
            info!("{}", Green.paint("Adding failed"));
        }

        result
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter))
        };

        let files  = self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file));
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files,
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: open
     */
    fn command_open(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Red};
        use open;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            Box::new(hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter)))
        };
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can open now: {:?}", file);
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url| {
                    if open::that(&url[..]).is_ok() {
                        info!("{}", Green.paint(format!("open({})", url)));
                        true
                    } else {
                        info!("{}", Red.paint(format!("could not open({})", url)));
                        false
                    }
                })
                .unwrap_or(false)
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (succ, fail) = result;
        info!("{}", Green.paint(format!("open() succeeded for {} files", succ)));
        info!("{}", Red.paint(format!(  "open() failed    for {} files", fail)));
        return fail == 0;
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Red};

        let parser = Parser::new(JsonHeaderParser::new(None));

        let filter = {
            let hash_filter = create_hash_filter(matches, "id", false);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", false);
            let tags_filter = create_tag_filter(matches, "tags", false);
            hash_filter.or(Box::new(text_filter)).or(Box::new(tags_filter))
        };

        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (worked, failed) = result;

        info!("{}", Green.paint(format!("Removing succeeded for {} files", worked)));
        info!("{}", Red.paint(format!(  "Removing failed for {} files", failed)));

        return failed == 0;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            cli_tags.clone()
        }, rebuild_header_with_tags)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("open") => {
                self.command_open(matches.subcommand_matches("open").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("{}", Red.bold().paint("No command given, doing nothing"));
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }

    fn runtime(&self) -> &Runtime {
        self.rt
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "BM"));
        Ok(())
    }

}

<|endoftext|>


<commit_before>pub mod problems;
pub mod functions;
pub mod constraints;
pub mod solvers;

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use math::variables::{new_var, new_const};
    use math::relationships::Relationship;
    use math::expressions::Expression;
    use objective::problems::ProblemType;
    use objective::functions::Function;
    use objective::constraints::Constraint;
    use objective::constraints::SystemOfConstraints;
    use objective::solvers::{transform_geq_rels, transform_leq_rels};

    #[test]
    fn can_create_problem_types() {
        let p_t_max: ProblemType = ProblemType::MAX;
        assert_eq!(ProblemType::MAX, p_t_max);
        let p_t_min: ProblemType = ProblemType::MIN;
        assert_eq!(ProblemType::MIN, p_t_min);
    }

    #[test]
    fn can_create_functions() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        let f: Function = Function::new(e, ProblemType::MAX);
        assert_eq!(ProblemType::MAX, *f.p_type());
        assert_eq!("Z", f.exp().lhs()[0].name());
        assert_eq!(1.0, f.exp().lhs()[0].coefficient());
        assert_eq!(Relationship::EQ, *f.exp().rel());
        assert_eq!("x", f.exp().rhs()[0].name());
        assert_eq!(2.0, f.exp().rhs()[0].coefficient());
        assert_eq!("y", f.exp().rhs()[1].name());
        assert_eq!(3.0, f.exp().rhs()[1].coefficient());
        assert_eq!("bonus", f.exp().rhs()[2].name());
        assert_eq!(1000.0, f.exp().rhs()[2].value());
    }

    #[test]
    fn can_create_constraints() {
        let e: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                            Relationship::LEQ,
                                            vec![new_const("volume", 2300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e));
        match c1 {
            Constraint::Regular(ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("x", exp.lhs()[0].name());
                assert_eq!(2.0, exp.lhs()[0].coefficient());
                assert_eq!(Relationship::LEQ, *exp.rel());
                assert_eq!("y", exp.lhs()[1].name());
                assert_eq!(3.0, exp.lhs()[1].coefficient());
                assert_eq!("volume", exp.rhs()[0].name());
                assert_eq!(2300.0, exp.rhs()[0].value());
            }
            _ => panic!("Unexpected variant."),
        }
        let c2: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        match c2 {
            Constraint::NonNegative(abst_var) => {
                assert_eq!("x", abst_var.name());
                assert_eq!(2.0, abst_var.coefficient());
            }
            _ => panic!("Unexpected variant."),
        }
    }

    #[test]
    fn can_create_system_of_constraints() {
        let e: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                            Relationship::LEQ,
                                            vec![new_const("volume", 2300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e));
        let c2: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        let s: SystemOfConstraints = SystemOfConstraints::new(vec![c1, c2]);
        for constraint in s.system() {
            match constraint {
                &Constraint::Regular(ref ref_cell) => {
                    let exp = ref_cell.borrow();
                    assert_eq!("x", exp.lhs()[0].name());
                    assert_eq!(2.0, exp.lhs()[0].coefficient());
                    assert_eq!(Relationship::LEQ, *exp.rel());
                    assert_eq!("y", exp.lhs()[1].name());
                    assert_eq!(3.0, exp.lhs()[1].coefficient());
                    assert_eq!("volume", exp.rhs()[0].name());
                    assert_eq!(2300.0, exp.rhs()[0].value());
                }
                &Constraint::NonNegative(ref abst_var) => {
                    assert_eq!("x", abst_var.name());
                    assert_eq!(2.0, abst_var.coefficient());
                }
            }
        }
    }

    #[test]
    fn can_transform_geq_rels() {
        let e1: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                             Relationship::LEQ,
                                             vec![new_const("volume", 2300.0)]);
        let e2: Expression = Expression::new(vec![new_var("w", 6.0), new_var("z", 9.0)],
                                             Relationship::GEQ,
                                             vec![new_const("area", 300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e1));
        let c2: Constraint = Constraint::Regular(RefCell::new(e2));
        let c3: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        let s: SystemOfConstraints = SystemOfConstraints::new(vec![c1, c2, c3]);
        transform_geq_rels(&s);
        match s.system()[0] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("x", exp.lhs()[0].name());
                assert_eq!(2.0, exp.lhs()[0].coefficient());
                assert_eq!(Relationship::LEQ, *exp.rel());
                assert_eq!("y", exp.lhs()[1].name());
                assert_eq!(3.0, exp.lhs()[1].coefficient());
                assert_eq!("volume", exp.rhs()[0].name());
                assert_eq!(2300.0, exp.rhs()[0].value());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[1] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("w", exp.lhs()[0].name());
                assert_eq!(-6.0, exp.lhs()[0].coefficient());
                assert_eq!(Relationship::LEQ, *exp.rel());
                assert_eq!("z", exp.lhs()[1].name());
                assert_eq!(-9.0, exp.lhs()[1].coefficient());
                assert_eq!("area", exp.rhs()[0].name());
                assert_eq!(-300.0, exp.rhs()[0].value());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[2] {
            Constraint::NonNegative(ref abst_var) => {
                assert_eq!("x", abst_var.name());
                assert_eq!(2.0, abst_var.coefficient());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
    }

    #[test]
    fn can_transform_leq_rels() {
        let e1: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                             Relationship::LEQ,
                                             vec![new_const("volume", 2300.0)]);
        let e2: Expression = Expression::new(vec![new_var("w", 6.0), new_var("z", 9.0)],
                                             Relationship::LEQ,
                                             vec![new_const("area", 300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e1));
        let c2: Constraint = Constraint::Regular(RefCell::new(e2));
        let c3: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        let s: SystemOfConstraints = SystemOfConstraints::new(vec![c1, c2, c3]);
        transform_leq_rels(&s);
        match s.system()[0] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("x", exp.lhs()[0].name());
                assert_eq!(2.0, exp.lhs()[0].coefficient());
                assert_eq!(Relationship::EQ, *exp.rel());
                assert_eq!("y", exp.lhs()[1].name());
                assert_eq!(3.0, exp.lhs()[1].coefficient());
                assert_eq!("s1", exp.lhs()[2].name());
                assert_eq!("volume", exp.rhs()[0].name());
                assert_eq!(2300.0, exp.rhs()[0].value());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[1] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("w", exp.lhs()[0].name());
                assert_eq!(6.0, exp.lhs()[0].coefficient());
                assert_eq!(Relationship::EQ, *exp.rel());
                assert_eq!("z", exp.lhs()[1].name());
                assert_eq!(9.0, exp.lhs()[1].coefficient());
                assert_eq!("s2", exp.lhs()[2].name());
                assert_eq!("area", exp.rhs()[0].name());
                assert_eq!(300.0, exp.rhs()[0].value());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[2] {
            Constraint::NonNegative(ref abst_var) => {
                assert_eq!("x", abst_var.name());
                assert_eq!(2.0, abst_var.coefficient());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
    }
}
<commit_msg>Finished refactoring setters and getters.<commit_after>pub mod problems;
pub mod functions;
pub mod constraints;
pub mod solvers;

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use math::variables::{new_var, new_const};
    use math::relationships::Relationship;
    use math::expressions::Expression;
    use objective::problems::ProblemType;
    use objective::functions::Function;
    use objective::constraints::Constraint;
    use objective::constraints::SystemOfConstraints;
    use objective::solvers::{transform_geq_rels, transform_leq_rels};

    #[test]
    fn can_create_problem_types() {
        let p_t_max: ProblemType = ProblemType::MAX;
        assert_eq!(ProblemType::MAX, p_t_max);
        let p_t_min: ProblemType = ProblemType::MIN;
        assert_eq!(ProblemType::MIN, p_t_min);
    }

    #[test]
    fn can_create_functions() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        let f: Function = Function::new(e, ProblemType::MAX);
        assert_eq!(ProblemType::MAX, *f.p_type());
        assert_eq!("Z", f.exp().lhs()[0].name());
        assert_eq!(1.0, f.exp().lhs()[0].get_data());
        assert_eq!(Relationship::EQ, *f.exp().rel());
        assert_eq!("x", f.exp().rhs()[0].name());
        assert_eq!(2.0, f.exp().rhs()[0].get_data());
        assert_eq!("y", f.exp().rhs()[1].name());
        assert_eq!(3.0, f.exp().rhs()[1].get_data());
        assert_eq!("bonus", f.exp().rhs()[2].name());
        assert_eq!(1000.0, f.exp().rhs()[2].get_data());
    }

    #[test]
    fn can_create_constraints() {
        let e: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                            Relationship::LEQ,
                                            vec![new_const("volume", 2300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e));
        match c1 {
            Constraint::Regular(ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("x", exp.lhs()[0].name());
                assert_eq!(2.0, exp.lhs()[0].get_data());
                assert_eq!(Relationship::LEQ, *exp.rel());
                assert_eq!("y", exp.lhs()[1].name());
                assert_eq!(3.0, exp.lhs()[1].get_data());
                assert_eq!("volume", exp.rhs()[0].name());
                assert_eq!(2300.0, exp.rhs()[0].get_data());
            }
            _ => panic!("Unexpected variant."),
        }
        let c2: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        match c2 {
            Constraint::NonNegative(abst_var) => {
                assert_eq!("x", abst_var.name());
                assert_eq!(2.0, abst_var.get_data());
            }
            _ => panic!("Unexpected variant."),
        }
    }

    #[test]
    fn can_create_system_of_constraints() {
        let e: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                            Relationship::LEQ,
                                            vec![new_const("volume", 2300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e));
        let c2: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        let s: SystemOfConstraints = SystemOfConstraints::new(vec![c1, c2]);
        for constraint in s.system() {
            match constraint {
                &Constraint::Regular(ref ref_cell) => {
                    let exp = ref_cell.borrow();
                    assert_eq!("x", exp.lhs()[0].name());
                    assert_eq!(2.0, exp.lhs()[0].get_data());
                    assert_eq!(Relationship::LEQ, *exp.rel());
                    assert_eq!("y", exp.lhs()[1].name());
                    assert_eq!(3.0, exp.lhs()[1].get_data());
                    assert_eq!("volume", exp.rhs()[0].name());
                    assert_eq!(2300.0, exp.rhs()[0].get_data());
                }
                &Constraint::NonNegative(ref abst_var) => {
                    assert_eq!("x", abst_var.name());
                    assert_eq!(2.0, abst_var.get_data());
                }
            }
        }
    }

    #[test]
    fn can_transform_geq_rels() {
        let e1: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                             Relationship::LEQ,
                                             vec![new_const("volume", 2300.0)]);
        let e2: Expression = Expression::new(vec![new_var("w", 6.0), new_var("z", 9.0)],
                                             Relationship::GEQ,
                                             vec![new_const("area", 300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e1));
        let c2: Constraint = Constraint::Regular(RefCell::new(e2));
        let c3: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        let s: SystemOfConstraints = SystemOfConstraints::new(vec![c1, c2, c3]);
        transform_geq_rels(&s);
        match s.system()[0] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("x", exp.lhs()[0].name());
                assert_eq!(2.0, exp.lhs()[0].get_data());
                assert_eq!(Relationship::LEQ, *exp.rel());
                assert_eq!("y", exp.lhs()[1].name());
                assert_eq!(3.0, exp.lhs()[1].get_data());
                assert_eq!("volume", exp.rhs()[0].name());
                assert_eq!(2300.0, exp.rhs()[0].get_data());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[1] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("w", exp.lhs()[0].name());
                assert_eq!(-6.0, exp.lhs()[0].get_data());
                assert_eq!(Relationship::LEQ, *exp.rel());
                assert_eq!("z", exp.lhs()[1].name());
                assert_eq!(-9.0, exp.lhs()[1].get_data());
                assert_eq!("area", exp.rhs()[0].name());
                assert_eq!(-300.0, exp.rhs()[0].get_data());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[2] {
            Constraint::NonNegative(ref abst_var) => {
                assert_eq!("x", abst_var.name());
                assert_eq!(2.0, abst_var.get_data());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
    }

    #[test]
    fn can_transform_leq_rels() {
        let e1: Expression = Expression::new(vec![new_var("x", 2.0), new_var("y", 3.0)],
                                             Relationship::LEQ,
                                             vec![new_const("volume", 2300.0)]);
        let e2: Expression = Expression::new(vec![new_var("w", 6.0), new_var("z", 9.0)],
                                             Relationship::LEQ,
                                             vec![new_const("area", 300.0)]);
        let c1: Constraint = Constraint::Regular(RefCell::new(e1));
        let c2: Constraint = Constraint::Regular(RefCell::new(e2));
        let c3: Constraint = Constraint::NonNegative(new_var("x", 2.0));
        let s: SystemOfConstraints = SystemOfConstraints::new(vec![c1, c2, c3]);
        transform_leq_rels(&s);
        match s.system()[0] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("x", exp.lhs()[0].name());
                assert_eq!(2.0, exp.lhs()[0].get_data());
                assert_eq!(Relationship::EQ, *exp.rel());
                assert_eq!("y", exp.lhs()[1].name());
                assert_eq!(3.0, exp.lhs()[1].get_data());
                assert_eq!("s1", exp.lhs()[2].name());
                assert_eq!("volume", exp.rhs()[0].name());
                assert_eq!(2300.0, exp.rhs()[0].get_data());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[1] {
            Constraint::Regular(ref ref_cell) => {
                let exp = ref_cell.borrow();
                assert_eq!("w", exp.lhs()[0].name());
                assert_eq!(6.0, exp.lhs()[0].get_data());
                assert_eq!(Relationship::EQ, *exp.rel());
                assert_eq!("z", exp.lhs()[1].name());
                assert_eq!(9.0, exp.lhs()[1].get_data());
                assert_eq!("s2", exp.lhs()[2].name());
                assert_eq!("area", exp.rhs()[0].name());
                assert_eq!(300.0, exp.rhs()[0].get_data());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
        match s.system()[2] {
            Constraint::NonNegative(ref abst_var) => {
                assert_eq!("x", abst_var.name());
                assert_eq!(2.0, abst_var.get_data());
            }
            _ => panic!("Unexpected variant in this program logic."),
        };
    }
}
<|endoftext|>


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

extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use self::bincode::SizeLimit;

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  u64,
    pub action:         u32,
    pub transaction_id: u32,
}

#[derive(RustcEncodable)]
struct ConnectionResponse {
    action:         u32,
    transaction_id: u32,
    connection_id:  u64,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: u64, tran_id: u32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}
<commit_msg>Add and decode ClientAnnounce packet<commit_after>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use self::bincode::SizeLimit;
use rustc_serialize::{Decodable, Decoder};

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  u64,
    pub action:         u32,
    pub transaction_id: u32,
}

#[derive(Debug, RustcEncodable)]
struct ConnectionResponse {
    action:         u32,
    transaction_id: u32,
    connection_id:  u64,
}

#[derive(Debug)]
struct ClientAnnounce {
    info_hash:  [u8; 20],
    peer_id:    [u8; 20],
    downloaded: i64,
    left:       i64,
    uploaded:   i64,
    event:      i32,
    ip:         u32,
    key:        u32,
    num_want:   i32,
    port:       u16,
}

impl Decodable for ClientAnnounce {
    fn decode<D: Decoder>(d: &mut D) -> Result<ClientAnnounce, D::Error> {
        let mut info_hash = [0u8; 20];
        for i in 0..20 {
            info_hash[i] = try!(d.read_u8());
        }
        let mut peer_id = [0u8; 20];
        for i in 0..20 {
            peer_id[i] = try!(d.read_u8());
        }
        Ok(ClientAnnounce {
            info_hash:  info_hash,
            peer_id:    peer_id,
            downloaded: try!(d.read_i64()),
            left:       try!(d.read_i64()),
            uploaded:   try!(d.read_i64()),
            event:      try!(d.read_i32()),
            ip:         try!(d.read_u32()),
            key:        try!(d.read_u32()),
            num_want:   try!(d.read_i32()),
            port:       try!(d.read_u16()),
        })
    }
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: u64, tran_id: u32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}

pub fn decode_client_announce(packet: &[u8]) -> ClientAnnounce {
    bincode::decode(&packet).unwrap()
}
<|endoftext|>


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

extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use self::bincode::SizeLimit;

pub struct PacketHeader {
    pub connection_id:  u64,
    pub action:         u32,
    pub transaction_id: u32,
}

#[derive(RustcEncodable)]
struct ConnectionResponse {
    action:         u32,
    transaction_id: u32,
    connection_id:  u64,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    let p_con_id            = &packet[0..8];
    let p_action            = &packet[8..12];
    let p_tran_id           = &packet[12..16];

    let mut connection_id:  u64 = 0;
    let mut action:         u32 = 0;
    let mut transaction_id: u32 = 0;

    for i in p_con_id.iter() {
        connection_id <<= 8;
        connection_id |= *i as u64;
    }

    for i in p_action.iter() {
        action <<= 8;
        action |= *i as u32;
    }

    for i in p_tran_id.iter() {
        transaction_id <<= 8;
        transaction_id |= *i as u32;
    }

    PacketHeader {connection_id: connection_id, action: action, transaction_id: transaction_id}
}

pub fn encode_connect_response(uuid: u64, tran_id: u32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};

    let encoded = bincode::encode(&packet, SizeLimit::Infinite).unwrap();
    encoded
}
<commit_msg>use bincode to de/encode packet data<commit_after>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use self::bincode::SizeLimit;

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  u64,
    pub action:         u32,
    pub transaction_id: u32,
}

#[derive(RustcEncodable)]
struct ConnectionResponse {
    action:         u32,
    transaction_id: u32,
    connection_id:  u64,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: u64, tran_id: u32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}
<|endoftext|>


<commit_before>use ascii::{AsAsciiStrError, AsciiChar, AsciiStr, ToAsciiChar, ToAsciiCharError};
use std::borrow::{Borrow, BorrowMut};
use std::cmp::{Eq, PartialEq};
use std::convert::{AsRef, AsMut, From, Into};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{fmt, mem, ptr, slice, str};
use ::{PascalStr, PASCAL_STRING_BUF_SIZE};

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length.
///
/// This string uses the Ascii encoding.
#[repr(C)]
pub struct PascalString {
    /// The length of this string.
    len: u8,
    /// The characters of this string, encoded as an ascii array.
    chars: [AsciiChar; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    /// Creates a new, empty `PascalString`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    #[inline]
    pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PascalStringError> {
        PascalString::_from_bytes(bytes.as_ref())
    }

    fn _from_bytes(bytes: &[u8]) -> Result<Self, PascalStringError>  {
        let len = bytes.len();
        if len > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringError::OutOfBounds);
        }
        // Perform ascii check
        let ascii = try!(AsciiStr::from_ascii(bytes));

        let mut string = PascalString::new();
        string.len = len as u8;
        for i in 0..len {
            string.chars[i] = ascii[i];
        }
        Ok(string)
    }

    /// Push an ascii convertible character onto this string.
    ///
    /// # Panics
    ///
    /// Panics if the string is full, of if the `character` is not a valid ascii character.
    #[inline]
    pub fn push<C: ToAsciiChar>(&mut self, character: C) {
        self.try_push(character).unwrap();
    }

    /// Attempt to push an ascii convertible character onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the character cannot be pushed because this `PascalString` is full, or if
    /// `character` is not a valid ascii character.
    #[inline]
    pub fn try_push<C: ToAsciiChar>(&mut self, character: C) -> Result<(), PascalStringError> {
        self._try_push(try!(AsciiChar::from(character)))
    }

    fn _try_push(&mut self, ch: AsciiChar) -> Result<(), PascalStringError> {
        if self.is_full() {
            return Err(PascalStringError::OutOfBounds)
        }
        self.chars[self.len as usize] = ch;
        self.len += 1;
        Ok(())
    }

    /// Append a given string slice onto the end of this `PascalString`.
    ///
    /// # Panics
    ///
    /// Panics if the string cannot be pushed to because this `PascalString` is full.
    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
        self.try_push_str(s).unwrap();
    }

    /// Attempt to append a given string slice onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the string cannot be pushed because this `PascalString` is full.
    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringError> {
        unimplemented!()
    }

    /// Removes the last character from the string buffer and returns it.
    ///
    /// Returns `None` if this `PascalString` is empty.
    pub fn pop(&mut self) -> Option<AsciiChar> {
        if self.is_empty() {
            return None;
        }
        let c = self.chars[self.len as usize];
        self.len -= 1;
        Some(c)
    }

    pub fn remove(&mut self, index: u8) -> AsciiChar {
        assert!(self.len < index);
        let len = self.len as usize;
        let index = index as isize;
        let c = self.chars[len];
        // Shift everything to the right of the removed character to the left to cover up the hole
        // left.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr.offset(1), ptr, len - index.abs() as usize - 1);
        }
        self.len -= 1;
        c
    }

    #[inline]
    pub fn insert<C: ToAsciiChar>(&mut self, ch: C, index: u8) {
        self._insert(AsciiChar::from(ch).unwrap(), index)
    }

    fn _insert(&mut self, ch: AsciiChar, index: u8) {
        assert!(self.len < index);
        assert!(!self.is_full());
        let len = self.len as usize;
        let index = index as isize;
        // Shift everything to the right of `index` 1 place to the right to make room for the
        // new character.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr, ptr.offset(1), len - index.abs() as usize - 1);
        }
        self.chars[len] = ch;
        self.len += 1;
    }

    /// Truncates this String, removing all contents.
    ///
    /// Does not zero the values of the string.
    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
    }

    /// Consumes this `PascalString`, and returns its inner state as a `[u8; 256]`, where the first byte
    /// is the length.
    ///
    /// Note that if the string has been truncated, bytes beyond the end of the string will not have been
    /// zeroed.
    #[inline]
    pub fn to_array(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        self.into()
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars: [AsciiChar::Null; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars, &mut clone.chars, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Eq for PascalString { }

impl PartialEq for PascalString {
    fn eq(&self, other: &PascalString) -> bool {
        if self.len != other.len {
            return false;
        }
        self.chars.iter().zip(other.chars.iter()).all(|(c0, c1)| c0 == c1)
    }
}

impl Hash for PascalString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(self.as_ref());
    }
}

impl fmt::Debug for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "{}", self)
    }
}

impl fmt::Display for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        fmtr.pad(self.as_ref())
    }
}

impl Deref for PascalString {
    type Target = PascalStr;
    fn deref(&self) -> &Self::Target {
        let ascii_str: &[AsciiChar] = self.as_ref();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl DerefMut for PascalString {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ascii_str: &mut [AsciiChar] = self.as_mut();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl AsRef<PascalStr> for PascalString {
    fn as_ref(&self) -> &PascalStr {
        self.deref()
    }
}

impl AsRef<str> for PascalString {
    fn as_ref(&self) -> &str {
        let bytes: &[u8] = self.as_ref();
        str::from_utf8(bytes).unwrap()
    }
}

impl AsRef<[u8]> for PascalString {
    fn as_ref(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr() as *const u8, self.len as usize)
        }
    }
}

impl AsRef<AsciiStr> for PascalString {
    fn as_ref(&self) -> &AsciiStr {
        let bytes: &[u8] = self.as_ref();
        AsciiStr::from_ascii(bytes).unwrap()
    }
}

impl AsRef<[AsciiChar]> for PascalString {
    fn as_ref(&self) -> &[AsciiChar] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr(), self.len as usize)
        }
    }
}

impl AsMut<[AsciiChar]> for PascalString {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        unsafe {
            slice::from_raw_parts_mut(self.chars.as_mut_ptr(), self.len as usize)
        }
    }
}

impl Borrow<PascalStr> for PascalString {
    fn borrow(&self) -> &PascalStr {
        self.deref()
    }
}

impl BorrowMut<PascalStr> for PascalString {
    fn borrow_mut(&mut self) -> &mut PascalStr {
        self.deref_mut()
    }
}

impl Borrow<str> for PascalString {
    fn borrow(&self) -> &str {
        self.as_ref()
    }
}

impl Borrow<[u8]> for PascalString {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl Borrow<AsciiStr> for PascalString {
    fn borrow(&self) -> &AsciiStr {
        self.as_ref()
    }
}

impl Borrow<[AsciiChar]> for PascalString {
    fn borrow(&self) -> &[AsciiChar] {
        self.as_ref()
    }
}

impl BorrowMut<[AsciiChar]> for PascalString {
    fn borrow_mut(&mut self) -> &mut [AsciiChar] {
        self.as_mut()
    }
}

impl Into<[u8; PASCAL_STRING_BUF_SIZE + 1]> for PascalString {
    fn into(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        let mut array = [0u8; PASCAL_STRING_BUF_SIZE + 1];
        array[0] = self.len;
        unsafe {
            let chars_ptr = &self.chars as *const _ as *const [u8; PASCAL_STRING_BUF_SIZE];
            let array_ptr = (&mut array as *mut _).offset(1) as *mut [u8; PASCAL_STRING_BUF_SIZE];
            ptr::copy_nonoverlapping(chars_ptr, array_ptr, PASCAL_STRING_BUF_SIZE);
        }
        array
    }
}

impl Into<String> for PascalString {
    fn into(self) -> String {
        String::from_utf8_lossy(self.as_ref()).into_owned()
    }
}

#[derive(Debug, PartialEq)]
pub enum PascalStringError {
    OutOfBounds,
    InvalidChar(ToAsciiCharError),
    InvalidString(AsAsciiStrError)
}

impl From<ToAsciiCharError> for PascalStringError {
    fn from(e: ToAsciiCharError) -> Self {
        PascalStringError::InvalidChar(e)
    }
}

impl From<AsAsciiStrError> for PascalStringError {
    fn from(e: AsAsciiStrError) -> Self {
        PascalStringError::InvalidString(e)
    }
}<commit_msg>Impl Index for PascalString with various index types.<commit_after>use ascii::{AsAsciiStrError, AsciiChar, AsciiStr, ToAsciiChar, ToAsciiCharError};
use std::borrow::{Borrow, BorrowMut};
use std::cmp::{Eq, PartialEq};
use std::convert::{AsRef, AsMut, From, Into};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::{fmt, mem, ptr, slice, str};
use ::{PascalStr, PASCAL_STRING_BUF_SIZE};

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length.
///
/// This string uses the Ascii encoding.
#[repr(C)]
pub struct PascalString {
    /// The length of this string.
    len: u8,
    /// The characters of this string, encoded as an ascii array.
    chars: [AsciiChar; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    /// Creates a new, empty `PascalString`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    #[inline]
    pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PascalStringError> {
        PascalString::_from_bytes(bytes.as_ref())
    }

    fn _from_bytes(bytes: &[u8]) -> Result<Self, PascalStringError>  {
        let len = bytes.len();
        if len > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringError::OutOfBounds);
        }
        // Perform ascii check
        let ascii = try!(AsciiStr::from_ascii(bytes));

        let mut string = PascalString::new();
        string.len = len as u8;
        for i in 0..len {
            string.chars[i] = ascii[i];
        }
        Ok(string)
    }

    /// Push an ascii convertible character onto this string.
    ///
    /// # Panics
    ///
    /// Panics if the string is full, of if the `character` is not a valid ascii character.
    #[inline]
    pub fn push<C: ToAsciiChar>(&mut self, character: C) {
        self.try_push(character).unwrap();
    }

    /// Attempt to push an ascii convertible character onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the character cannot be pushed because this `PascalString` is full, or if
    /// `character` is not a valid ascii character.
    #[inline]
    pub fn try_push<C: ToAsciiChar>(&mut self, character: C) -> Result<(), PascalStringError> {
        self._try_push(try!(AsciiChar::from(character)))
    }

    fn _try_push(&mut self, ch: AsciiChar) -> Result<(), PascalStringError> {
        if self.is_full() {
            return Err(PascalStringError::OutOfBounds)
        }
        self.chars[self.len as usize] = ch;
        self.len += 1;
        Ok(())
    }

    /// Append a given string slice onto the end of this `PascalString`.
    ///
    /// # Panics
    ///
    /// Panics if the string cannot be pushed to because this `PascalString` is full.
    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
        self.try_push_str(s).unwrap();
    }

    /// Attempt to append a given string slice onto the end of this `PascalString`.
    ///
    /// Returns `Err(_)` if the string cannot be pushed because this `PascalString` is full.
    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringError> {
        unimplemented!()
    }

    /// Removes the last character from the string buffer and returns it.
    ///
    /// Returns `None` if this `PascalString` is empty.
    pub fn pop(&mut self) -> Option<AsciiChar> {
        if self.is_empty() {
            return None;
        }
        let c = self.chars[self.len as usize];
        self.len -= 1;
        Some(c)
    }

    pub fn remove(&mut self, index: u8) -> AsciiChar {
        assert!(self.len < index);
        let len = self.len as usize;
        let index = index as isize;
        let c = self.chars[len];
        // Shift everything to the right of the removed character to the left to cover up the hole
        // left.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr.offset(1), ptr, len - index.abs() as usize - 1);
        }
        self.len -= 1;
        c
    }

    #[inline]
    pub fn insert<C: ToAsciiChar>(&mut self, ch: C, index: u8) {
        self._insert(AsciiChar::from(ch).unwrap(), index)
    }

    fn _insert(&mut self, ch: AsciiChar, index: u8) {
        assert!(self.len < index);
        assert!(!self.is_full());
        let len = self.len as usize;
        let index = index as isize;
        // Shift everything to the right of `index` 1 place to the right to make room for the
        // new character.
        unsafe {
            let ptr = self.as_mut_ptr().offset(index);
            ptr::copy(ptr, ptr.offset(1), len - index.abs() as usize - 1);
        }
        self.chars[len] = ch;
        self.len += 1;
    }

    /// Truncates this String, removing all contents.
    ///
    /// Does not zero the values of the string.
    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
    }

    /// Consumes this `PascalString`, and returns its inner state as a `[u8; 256]`, where the first byte
    /// is the length.
    ///
    /// Note that if the string has been truncated, bytes beyond the end of the string will not have been
    /// zeroed.
    #[inline]
    pub fn to_array(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        self.into()
    }

    #[inline]
    pub fn get_unchecked(&self, index: u8) -> AsciiChar {
        self.chars[index as usize]
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars: [AsciiChar::Null; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars, &mut clone.chars, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Eq for PascalString { }

impl PartialEq for PascalString {
    fn eq(&self, other: &PascalString) -> bool {
        if self.len != other.len {
            return false;
        }
        self.chars.iter().zip(other.chars.iter()).all(|(c0, c1)| c0 == c1)
    }
}

impl Hash for PascalString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(self.as_ref());
    }
}

impl fmt::Debug for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "{}", self)
    }
}

impl fmt::Display for PascalString {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        fmtr.pad(self.as_ref())
    }
}

impl Index<u8> for PascalString {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        assert!(index < self.len);
        &self.chars[index as usize]
    }
}

impl IndexMut<u8> for PascalString {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        assert!(index < self.len);
        &mut self.chars[index as usize]
    }
}

impl Index<usize> for PascalString {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.chars[index]
    }
}

impl IndexMut<usize> for PascalString {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.chars[index]
    }
}

impl Index<RangeFull> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, _: RangeFull) -> &Self::Output {
        &self.chars
    }
}

impl IndexMut<RangeFull> for PascalString {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        &mut self.chars
    }
}

impl Index<Range<u8>> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!(range.end < self.len);
        &self.chars[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalString {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!(range.end < self.len);
        &mut self.chars[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.chars[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalString {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.chars[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        &self.chars[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalString {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        &mut self.chars[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        &self.chars[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalString {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        &mut self.chars[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!(range.end < self.len);
        &self.chars[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalString {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!(range.end < self.len);
        &mut self.chars[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalString {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.chars[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalString {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.chars[..range.end]
    }
}

impl Deref for PascalString {
    type Target = PascalStr;
    fn deref(&self) -> &Self::Target {
        let ascii_str: &[AsciiChar] = self.as_ref();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl DerefMut for PascalString {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let ascii_str: &mut [AsciiChar] = self.as_mut();
        unsafe {
            mem::transmute(ascii_str)
        }
    }
}

impl AsRef<PascalStr> for PascalString {
    fn as_ref(&self) -> &PascalStr {
        self.deref()
    }
}

impl AsRef<str> for PascalString {
    fn as_ref(&self) -> &str {
        let bytes: &[u8] = self.as_ref();
        str::from_utf8(bytes).unwrap()
    }
}

impl AsRef<[u8]> for PascalString {
    fn as_ref(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr() as *const u8, self.len as usize)
        }
    }
}

impl AsRef<AsciiStr> for PascalString {
    fn as_ref(&self) -> &AsciiStr {
        let bytes: &[u8] = self.as_ref();
        AsciiStr::from_ascii(bytes).unwrap()
    }
}

impl AsRef<[AsciiChar]> for PascalString {
    fn as_ref(&self) -> &[AsciiChar] {
        unsafe {
            slice::from_raw_parts(self.chars.as_ptr(), self.len as usize)
        }
    }
}

impl AsMut<[AsciiChar]> for PascalString {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        unsafe {
            slice::from_raw_parts_mut(self.chars.as_mut_ptr(), self.len as usize)
        }
    }
}

impl Borrow<PascalStr> for PascalString {
    fn borrow(&self) -> &PascalStr {
        self.deref()
    }
}

impl BorrowMut<PascalStr> for PascalString {
    fn borrow_mut(&mut self) -> &mut PascalStr {
        self.deref_mut()
    }
}

impl Borrow<str> for PascalString {
    fn borrow(&self) -> &str {
        self.as_ref()
    }
}

impl Borrow<[u8]> for PascalString {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl Borrow<AsciiStr> for PascalString {
    fn borrow(&self) -> &AsciiStr {
        self.as_ref()
    }
}

impl Borrow<[AsciiChar]> for PascalString {
    fn borrow(&self) -> &[AsciiChar] {
        self.as_ref()
    }
}

impl BorrowMut<[AsciiChar]> for PascalString {
    fn borrow_mut(&mut self) -> &mut [AsciiChar] {
        self.as_mut()
    }
}

impl Into<[u8; PASCAL_STRING_BUF_SIZE + 1]> for PascalString {
    fn into(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
        let mut array = [0u8; PASCAL_STRING_BUF_SIZE + 1];
        array[0] = self.len;
        unsafe {
            let chars_ptr = &self.chars as *const _ as *const [u8; PASCAL_STRING_BUF_SIZE];
            let array_ptr = (&mut array as *mut _).offset(1) as *mut [u8; PASCAL_STRING_BUF_SIZE];
            ptr::copy_nonoverlapping(chars_ptr, array_ptr, PASCAL_STRING_BUF_SIZE);
        }
        array
    }
}

impl Into<String> for PascalString {
    fn into(self) -> String {
        String::from_utf8_lossy(self.as_ref()).into_owned()
    }
}

#[derive(Debug, PartialEq)]
pub enum PascalStringError {
    OutOfBounds,
    InvalidChar(ToAsciiCharError),
    InvalidString(AsAsciiStrError)
}

impl From<ToAsciiCharError> for PascalStringError {
    fn from(e: ToAsciiCharError) -> Self {
        PascalStringError::InvalidChar(e)
    }
}

impl From<AsAsciiStrError> for PascalStringError {
    fn from(e: AsAsciiStrError) -> Self {
        PascalStringError::InvalidString(e)
    }
}<|endoftext|>