<commit_before>use nom;

#[derive(Debug, PartialEq)]
pub enum Hashline {
    OpenEnv(Environment),
    PlainLine(String),
}

#[derive(Debug, PartialEq)]
pub struct Environment {
    indent_depth: usize,
    name: String,
    opts: String,
    comment: String,
    is_list_like: bool,
}

impl Environment {
    pub fn latex_begin(&self) -> String {
        format!(r"{:ind$}\begin{{{}}}{}{:comment_sep$}{}",
                "",
                self.name,
                self.opts,
                "",
                self.comment,
                ind = self.indent_depth,
                comment_sep = if self.comment.is_empty() { 0 } else { 1 })
    }

    pub fn latex_end(&self) -> String {
        format!(r"{:ind$}\end{{{}}}", "", self.name, ind = self.indent_depth)
    }

    pub fn indent_depth(&self) -> usize {
        self.indent_depth
    }

    pub fn is_list_like(&self) -> bool {
        self.is_list_like
    }
}

// Hashline parsers
named!(
    list_env_parser<&[u8]>,
    ws!(alt!(tag!("itemize") | tag!("enumerate") | tag!("description")))
);
named!(escaped_colon<u8>, preceded!(specific_byte!('\\' as u8), specific_byte!(':' as u8)));
named!(escaped_percent<u8>, preceded!(specific_byte!('\\' as u8), specific_byte!('%' as u8)));
named!(name_parser<u8>, alt!(escaped_colon | none_of_bytes_as_bytes!(b":%([{ \t")));
named!(opts_parser<u8>, alt!(escaped_colon | escaped_percent | none_of_bytes_as_bytes!(b":%")));
named!(args_parser<u8>, alt!(escaped_percent | none_of_bytes_as_bytes!(b"%")));
named!(
    hashline_parser<Hashline>,
    do_parse!(
        ws: opt!(is_a!(" ")) >>
        tag!("# ") >>
        name: many1!(name_parser) >>
        opts: many0!(opts_parser) >>
        tag!(":") >>
        args: many0!(args_parser) >>
        comment: call!(nom::rest) >>
        (hashline_helper(ws.unwrap_or(&b""[..]), &name, &opts, &args, &comment))
    )
);
#[inline]
fn hashline_helper(ws: &[u8], name: &[u8], opts: &[u8], args: &[u8], comment: &[u8]) -> Hashline {
    use std::str::from_utf8;
    use self::Hashline::{PlainLine, OpenEnv};

    // It is ok to unwrap here, since we have checked for UTF-8 when we read the file
    let name_utf8 = from_utf8(name).unwrap().trim();
    let opts_utf8 = from_utf8(opts).unwrap().trim().replace("%", r"\%");
    let args_utf8 = from_utf8(args).unwrap().trim().replace("%", r"\%");
    let comment_utf8 = from_utf8(comment).unwrap().trim();

    if args_utf8.is_empty() {
        // If no args are given, it's an environment
        let env = Environment {
            indent_depth: ws.len(),
            name: name_utf8.to_string(),
            opts: opts_utf8.to_string(),
            comment: comment_utf8.to_string(),
            is_list_like: list_env_parser(name).is_done(),
        };
        OpenEnv(env)
    } else {
        // If there are some args, it's a single-line command
        let ws_utf8 = from_utf8(ws).unwrap();
        PlainLine(format!(r"{}\{}{}{{{}}}{:comment_sep$}{}",
                          ws_utf8,
                          name_utf8,
                          opts_utf8,
                          args_utf8,
                          "",
                          comment_utf8,
                          comment_sep = if comment_utf8.is_empty() { 0 } else { 1 }))
    }
}

// Hashline processing
#[inline]
fn process_hashline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    use nom::IResult::{Done, Error, Incomplete};

    match hashline_parser(line.as_ref().as_bytes()) {
        Done(_, r) => Some(r),
        Error(_) | Incomplete(_) => None,
    }
}

// Itemline parsers
named!(
    itemline_parser<Hashline>,
    do_parse!(
        ws: opt!(is_a!(" ")) >>
        tag!("*") >>
        item: call!(nom::rest) >>
        (itemline_helper(ws.unwrap_or(&b""[..]), item))
    )
);
#[inline]
fn itemline_helper(ws: &[u8], item: &[u8]) -> Hashline {
    use std::str::from_utf8;
    use self::Hashline::PlainLine;

    let ws_utf8 = from_utf8(ws).unwrap();
    let item_utf8 = from_utf8(item).unwrap().trim();

    PlainLine(format!(r"{}\item{:item_sep$}{}",
                      ws_utf8,
                      "",
                      item_utf8,
                      item_sep = if item_utf8.is_empty() { 0 } else { 1 }))
}

// Itemline processing
#[inline]
fn process_itemline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    use nom::IResult::{Done, Error, Incomplete};

    match itemline_parser(line.as_ref().as_bytes()) {
        Done(_, r) => Some(r),
        Error(_) | Incomplete(_) => None,
    }
}

// Fully process line
pub fn process_line<T>(line: T, list_like_active: bool) -> Hashline
    where T: AsRef<str>
{
    use self::Hashline::PlainLine;

    match process_hashline(&line) {
        Some(r) => r,
        None => {
            if list_like_active {
                match process_itemline(&line) {
                    Some(r) => r,
                    None => PlainLine(line.as_ref().to_string()),
                }
            } else {
                PlainLine(line.as_ref().to_string())
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use nom::IResult::{Done, Error, Incomplete};
    use nom::{ErrorKind, Needed};

    #[test]
    fn itemline_helper() {
        use super::{Hashline, itemline_helper};

        assert_eq!(itemline_helper(&b"  "[..], &b"foo"[..]),
                   Hashline::PlainLine("  \\item foo".to_string()));
        // Test that no whitespace is put after `\item` if no item is given
        assert_eq!(itemline_helper(&b" "[..], &b""[..]),
                   Hashline::PlainLine(" \\item".to_string()));
    }

    #[test]
    fn process_itemline() {
        use super::{Hashline, process_itemline};

        // Valid itemlines
        assert_eq!(process_itemline("*"),
                   Some(Hashline::PlainLine("\\item".to_string())));
        assert_eq!(process_itemline("*  "),
                   Some(Hashline::PlainLine("\\item".to_string())));
        assert_eq!(process_itemline("  *"),
                   Some(Hashline::PlainLine("  \\item".to_string())));
        assert_eq!(process_itemline("  *  "),
                   Some(Hashline::PlainLine("  \\item".to_string())));
        assert_eq!(process_itemline("* foo"),
                   Some(Hashline::PlainLine("\\item foo".to_string())));
        assert_eq!(process_itemline("  * bar"),
                   Some(Hashline::PlainLine("  \\item bar".to_string())));
        assert_eq!(process_itemline("****"),
                   Some(Hashline::PlainLine("\\item ***".to_string())));

        // Not an itemline
        assert_eq!(process_itemline("  baz"), None);
        assert_eq!(process_itemline("qux *"), None);
        assert_eq!(process_itemline("  abc * def"), None);
        assert_eq!(process_itemline("  \\*  "), None);
        assert_eq!(process_itemline("\\*  "), None);
    }

    #[test]
    fn environment_methods() {
        use super::Environment;

        let env_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "% baz".to_string(),
            is_list_like: true,
        };

        assert_eq!(env_1.latex_begin(), "\\begin{foo}bar % baz");
        assert_eq!(env_1.latex_end(), "\\end{foo}");
        assert_eq!(env_1.is_list_like(), true);
        assert_eq!(env_1.indent_depth(), 0);

        let env_2 = Environment {
            indent_depth: 2,
            name: "abc".to_string(),
            opts: "def".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };

        assert_eq!(env_2.latex_begin(), "  \\begin{abc}def");
        assert_eq!(env_2.latex_end(), "  \\end{abc}");
        assert_eq!(env_2.is_list_like(), false);
        assert_eq!(env_2.indent_depth(), 2);
    }

    #[test]
    fn list_env_parser() {
        use super::list_env_parser;

        let a = b"itemize";
        let b = b"enumerate*";
        let c = b"    description  *";
        let d = b"item";
        let e = b"foobar";

        assert_eq!(list_env_parser(&a[..]), Done(&b""[..], &a[..]));
        assert_eq!(list_env_parser(&b[..]), Done(&b"*"[..], &b"enumerate"[..]));
        assert_eq!(list_env_parser(&c[..]), Done(&b"*"[..], &b"description"[..]));
        assert_eq!(list_env_parser(&d[..]), Incomplete(Needed::Size(7)));
        assert_eq!(list_env_parser(&e[..]), Error(error_position!(ErrorKind::Alt, &e[..])));
    }

    #[test]
    fn escaped_colon() {
        use super::escaped_colon;

        let a = br"\:";
        let b = b"";
        let c = b"ab";

        assert_eq!(escaped_colon(&a[..]), Done(&b""[..], ':' as u8));
        assert_eq!(escaped_colon(&b[..]), Incomplete(Needed::Size(1)));
        assert_eq!(escaped_colon(&c[..]), Error(error_position!(ErrorKind::Char, &c[..])));
    }

    #[test]
    fn escaped_percent() {
        use super::escaped_percent;

        let a = br"\%";
        let b = b"";
        let c = b"ab";

        assert_eq!(escaped_percent(&a[..]), Done(&b""[..], '%' as u8));
        assert_eq!(escaped_percent(&b[..]), Incomplete(Needed::Size(1)));
        assert_eq!(escaped_percent(&c[..]), Error(error_position!(ErrorKind::Char, &c[..])));
    }

    #[test]
    fn name_parser() {
        use super::name_parser;

        assert_eq!(name_parser(&br"abc"[..]), Done(&b"bc"[..], 'a' as u8));
        assert_eq!(name_parser(&br"\:abc"[..]), Done(&b"abc"[..], ':' as u8));
        assert_eq!(name_parser(&b""[..]), Incomplete(Needed::Size(1)));

        for e in vec![b":E", b"%E", b"(E", b"[E", b"{E", b" E", b"\tE"] {
            assert_eq!(name_parser(&e[..]), Error(error_position!(ErrorKind::Alt, &e[..])));
        }
    }

    #[test]
    fn opts_parser() {
        use super::opts_parser;

        assert_eq!(opts_parser(&br"abc"[..]), Done(&b"bc"[..], 'a' as u8));
        assert_eq!(opts_parser(&br"\:abc"[..]), Done(&b"abc"[..], ':' as u8));
        assert_eq!(opts_parser(&br"\%abc"[..]), Done(&b"abc"[..], '%' as u8));
        assert_eq!(opts_parser(&br"(abc"[..]), Done(&b"abc"[..], '(' as u8));
        assert_eq!(opts_parser(&br"[abc"[..]), Done(&b"abc"[..], '[' as u8));
        assert_eq!(opts_parser(&br" abc"[..]), Done(&b"abc"[..], ' ' as u8));
        assert_eq!(opts_parser(&b""[..]), Incomplete(Needed::Size(1)));

        for e in vec![b":E", b"%E"] {
            assert_eq!(opts_parser(&e[..]), Error(error_position!(ErrorKind::Alt, &e[..])));
        }
    }

    #[test]
    fn args_parser() {
        use super::args_parser;

        assert_eq!(args_parser(&br"abc"[..]), Done(&b"bc"[..], 'a' as u8));
        assert_eq!(args_parser(&br"\:abc"[..]), Done(&b":abc"[..], '\\' as u8));
        assert_eq!(args_parser(&br"\%abc"[..]), Done(&b"abc"[..], '%' as u8));
        assert_eq!(args_parser(&br"(abc"[..]), Done(&b"abc"[..], '(' as u8));
        assert_eq!(args_parser(&br"[abc"[..]), Done(&b"abc"[..], '[' as u8));
        assert_eq!(args_parser(&br" abc"[..]), Done(&b"abc"[..], ' ' as u8));
        assert_eq!(args_parser(&b""[..]), Incomplete(Needed::Size(1)));

        assert_eq!(args_parser(&b"%E"[..]), Error(error_position!(ErrorKind::Alt, &b"%E"[..])));
    }
}
<commit_msg>Added unit tests for the hashline helper parser<commit_after>use nom;

#[derive(Debug, PartialEq)]
pub enum Hashline {
    OpenEnv(Environment),
    PlainLine(String),
}

#[derive(Debug, PartialEq)]
pub struct Environment {
    indent_depth: usize,
    name: String,
    opts: String,
    comment: String,
    is_list_like: bool,
}

impl Environment {
    pub fn latex_begin(&self) -> String {
        format!(r"{:ind$}\begin{{{}}}{}{:comment_sep$}{}",
                "",
                self.name,
                self.opts,
                "",
                self.comment,
                ind = self.indent_depth,
                comment_sep = if self.comment.is_empty() { 0 } else { 1 })
    }

    pub fn latex_end(&self) -> String {
        format!(r"{:ind$}\end{{{}}}", "", self.name, ind = self.indent_depth)
    }

    pub fn indent_depth(&self) -> usize {
        self.indent_depth
    }

    pub fn is_list_like(&self) -> bool {
        self.is_list_like
    }
}

// Hashline parsers
named!(
    list_env_parser<&[u8]>,
    ws!(alt!(tag!("itemize") | tag!("enumerate") | tag!("description")))
);
named!(escaped_colon<u8>, preceded!(specific_byte!('\\' as u8), specific_byte!(':' as u8)));
named!(escaped_percent<u8>, preceded!(specific_byte!('\\' as u8), specific_byte!('%' as u8)));
named!(name_parser<u8>, alt!(escaped_colon | none_of_bytes_as_bytes!(b":%([{ \t")));
named!(opts_parser<u8>, alt!(escaped_colon | escaped_percent | none_of_bytes_as_bytes!(b":%")));
named!(args_parser<u8>, alt!(escaped_percent | none_of_bytes_as_bytes!(b"%")));
named!(
    hashline_parser<Hashline>,
    do_parse!(
        ws: opt!(is_a!(" ")) >>
        tag!("# ") >>
        name: many1!(name_parser) >>
        opts: many0!(opts_parser) >>
        tag!(":") >>
        args: many0!(args_parser) >>
        comment: call!(nom::rest) >>
        (hashline_helper(ws.unwrap_or(&b""[..]), &name, &opts, &args, &comment))
    )
);
#[inline]
fn hashline_helper(ws: &[u8], name: &[u8], opts: &[u8], args: &[u8], comment: &[u8]) -> Hashline {
    use std::str::from_utf8;
    use self::Hashline::{PlainLine, OpenEnv};

    // It is ok to unwrap here, since we have checked for UTF-8 when we read the file
    let name_utf8 = from_utf8(name).unwrap().trim();
    let opts_utf8 = from_utf8(opts).unwrap().trim().replace("%", r"\%");
    let args_utf8 = from_utf8(args).unwrap().trim().replace("%", r"\%");
    let comment_utf8 = from_utf8(comment).unwrap().trim();

    if args_utf8.is_empty() {
        // If no args are given, it's an environment
        let env = Environment {
            indent_depth: ws.len(),
            name: name_utf8.to_string(),
            opts: opts_utf8.to_string(),
            comment: comment_utf8.to_string(),
            is_list_like: list_env_parser(name).is_done(),
        };
        OpenEnv(env)
    } else {
        // If there are some args, it's a single-line command
        let ws_utf8 = from_utf8(ws).unwrap();
        PlainLine(format!(r"{}\{}{}{{{}}}{:comment_sep$}{}",
                          ws_utf8,
                          name_utf8,
                          opts_utf8,
                          args_utf8,
                          "",
                          comment_utf8,
                          comment_sep = if comment_utf8.is_empty() { 0 } else { 1 }))
    }
}

// Hashline processing
#[inline]
fn process_hashline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    use nom::IResult::{Done, Error, Incomplete};

    match hashline_parser(line.as_ref().as_bytes()) {
        Done(_, r) => Some(r),
        Error(_) | Incomplete(_) => None,
    }
}

// Itemline parsers
named!(
    itemline_parser<Hashline>,
    do_parse!(
        ws: opt!(is_a!(" ")) >>
        tag!("*") >>
        item: call!(nom::rest) >>
        (itemline_helper(ws.unwrap_or(&b""[..]), item))
    )
);
#[inline]
fn itemline_helper(ws: &[u8], item: &[u8]) -> Hashline {
    use std::str::from_utf8;
    use self::Hashline::PlainLine;

    let ws_utf8 = from_utf8(ws).unwrap();
    let item_utf8 = from_utf8(item).unwrap().trim();

    PlainLine(format!(r"{}\item{:item_sep$}{}",
                      ws_utf8,
                      "",
                      item_utf8,
                      item_sep = if item_utf8.is_empty() { 0 } else { 1 }))
}

// Itemline processing
#[inline]
fn process_itemline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    use nom::IResult::{Done, Error, Incomplete};

    match itemline_parser(line.as_ref().as_bytes()) {
        Done(_, r) => Some(r),
        Error(_) | Incomplete(_) => None,
    }
}

// Fully process line
pub fn process_line<T>(line: T, list_like_active: bool) -> Hashline
    where T: AsRef<str>
{
    use self::Hashline::PlainLine;

    match process_hashline(&line) {
        Some(r) => r,
        None => {
            if list_like_active {
                match process_itemline(&line) {
                    Some(r) => r,
                    None => PlainLine(line.as_ref().to_string()),
                }
            } else {
                PlainLine(line.as_ref().to_string())
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use nom::IResult::{Done, Error, Incomplete};
    use nom::{ErrorKind, Needed};

    macro_rules! nil { () => ("".as_bytes()); }
    macro_rules! ws_1 { () => (" ".as_bytes()); }
    macro_rules! ws_2 { () => ("  ".as_bytes()); }
    macro_rules! ws_4 { () => ("    ".as_bytes()); }

    macro_rules! foo { () => ("foo".as_bytes()); }
    macro_rules! bar { () => ("bar".as_bytes()); }
    macro_rules! qux { () => ("qux".as_bytes()); }

    #[test]
    fn hashline_helper_plain_lines() {
        use super::{Hashline, hashline_helper};

        assert_eq!(hashline_helper(nil!(), foo!(), nil!(), bar!(), nil!()),
                   Hashline::PlainLine("\\foo{bar}".to_string()));
        assert_eq!(hashline_helper(ws_2!(), foo!(), nil!(), bar!(), qux!()),
                   Hashline::PlainLine("  \\foo{bar} qux".to_string()));
        assert_eq!(hashline_helper(ws_4!(), foo!(), bar!(), qux!(), nil!()),
                   Hashline::PlainLine("    \\foobar{qux}".to_string()));
    }

    #[test]
    fn hashline_helper_environments() {
        use super::{Hashline, Environment, hashline_helper};

        let env_ref_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };
        assert_eq!(hashline_helper(nil!(), foo!(), bar!(), nil!(), nil!()),
                   Hashline::OpenEnv(env_ref_1));

        let env_ref_2 = Environment {
            indent_depth: 2,
            name: "foo".to_string(),
            opts: "".to_string(),
            comment: "bar".to_string(),
            is_list_like: false,
        };
        assert_eq!(hashline_helper(ws_2!(), foo!(), nil!(), nil!(), bar!()),
                   Hashline::OpenEnv(env_ref_2));

        let env_ref_3 = Environment {
            indent_depth: 4,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "qux".to_string(),
            is_list_like: false,
        };
        assert_eq!(hashline_helper(ws_4!(), foo!(), bar!(), nil!(), qux!()),
                   Hashline::OpenEnv(env_ref_3));
    }

    #[test]
    fn itemline_helper() {
        use super::{Hashline, itemline_helper};

        assert_eq!(itemline_helper(ws_2!(), foo!()),
                   Hashline::PlainLine("  \\item foo".to_string()));
        // Test that no whitespace is put after `\item` if no item is given
        assert_eq!(itemline_helper(ws_1!(), nil!()),
                   Hashline::PlainLine(" \\item".to_string()));
    }

    #[test]
    fn process_itemline() {
        use super::{Hashline, process_itemline};

        // Valid itemlines
        assert_eq!(process_itemline("*"),
                   Some(Hashline::PlainLine("\\item".to_string())));
        assert_eq!(process_itemline("*  "),
                   Some(Hashline::PlainLine("\\item".to_string())));
        assert_eq!(process_itemline("  *"),
                   Some(Hashline::PlainLine("  \\item".to_string())));
        assert_eq!(process_itemline("  *  "),
                   Some(Hashline::PlainLine("  \\item".to_string())));
        assert_eq!(process_itemline("* foo"),
                   Some(Hashline::PlainLine("\\item foo".to_string())));
        assert_eq!(process_itemline("  * bar"),
                   Some(Hashline::PlainLine("  \\item bar".to_string())));
        assert_eq!(process_itemline("****"),
                   Some(Hashline::PlainLine("\\item ***".to_string())));

        // Not an itemline
        assert_eq!(process_itemline("  baz"), None);
        assert_eq!(process_itemline("qux *"), None);
        assert_eq!(process_itemline("  abc * def"), None);
        assert_eq!(process_itemline("  \\*  "), None);
        assert_eq!(process_itemline("\\*  "), None);
    }

    #[test]
    fn environment_methods() {
        use super::Environment;

        let env_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "% baz".to_string(),
            is_list_like: true,
        };

        assert_eq!(env_1.latex_begin(), "\\begin{foo}bar % baz");
        assert_eq!(env_1.latex_end(), "\\end{foo}");
        assert_eq!(env_1.is_list_like(), true);
        assert_eq!(env_1.indent_depth(), 0);

        let env_2 = Environment {
            indent_depth: 2,
            name: "abc".to_string(),
            opts: "def".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };

        assert_eq!(env_2.latex_begin(), "  \\begin{abc}def");
        assert_eq!(env_2.latex_end(), "  \\end{abc}");
        assert_eq!(env_2.is_list_like(), false);
        assert_eq!(env_2.indent_depth(), 2);
    }

    #[test]
    fn list_env_parser() {
        use super::list_env_parser;

        let a = b"itemize";
        let b = b"enumerate*";
        let c = b"    description  *";
        let d = b"item";
        let e = b"foobar";

        assert_eq!(list_env_parser(&a[..]), Done(&b""[..], &a[..]));
        assert_eq!(list_env_parser(&b[..]), Done(&b"*"[..], &b"enumerate"[..]));
        assert_eq!(list_env_parser(&c[..]), Done(&b"*"[..], &b"description"[..]));
        assert_eq!(list_env_parser(&d[..]), Incomplete(Needed::Size(7)));
        assert_eq!(list_env_parser(&e[..]), Error(error_position!(ErrorKind::Alt, &e[..])));
    }

    #[test]
    fn escaped_colon() {
        use super::escaped_colon;

        let a = br"\:";
        let c = b"ab";

        assert_eq!(escaped_colon(&a[..]), Done(&b""[..], ':' as u8));
        assert_eq!(escaped_colon(nil!()), Incomplete(Needed::Size(1)));
        assert_eq!(escaped_colon(&c[..]), Error(error_position!(ErrorKind::Char, &c[..])));
    }

    #[test]
    fn escaped_percent() {
        use super::escaped_percent;

        let a = br"\%";
        let c = b"ab";

        assert_eq!(escaped_percent(&a[..]), Done(&b""[..], '%' as u8));
        assert_eq!(escaped_percent(nil!()), Incomplete(Needed::Size(1)));
        assert_eq!(escaped_percent(&c[..]), Error(error_position!(ErrorKind::Char, &c[..])));
    }

    #[test]
    fn name_parser() {
        use super::name_parser;

        assert_eq!(name_parser(&br"abc"[..]), Done(&b"bc"[..], 'a' as u8));
        assert_eq!(name_parser(&br"\:abc"[..]), Done(&b"abc"[..], ':' as u8));
        assert_eq!(name_parser(&b""[..]), Incomplete(Needed::Size(1)));

        for e in vec![b":E", b"%E", b"(E", b"[E", b"{E", b" E", b"\tE"] {
            assert_eq!(name_parser(&e[..]), Error(error_position!(ErrorKind::Alt, &e[..])));
        }
    }

    #[test]
    fn opts_parser() {
        use super::opts_parser;

        assert_eq!(opts_parser(&br"abc"[..]), Done(&b"bc"[..], 'a' as u8));
        assert_eq!(opts_parser(&br"\:abc"[..]), Done(&b"abc"[..], ':' as u8));
        assert_eq!(opts_parser(&br"\%abc"[..]), Done(&b"abc"[..], '%' as u8));
        assert_eq!(opts_parser(&br"(abc"[..]), Done(&b"abc"[..], '(' as u8));
        assert_eq!(opts_parser(&br"[abc"[..]), Done(&b"abc"[..], '[' as u8));
        assert_eq!(opts_parser(&br" abc"[..]), Done(&b"abc"[..], ' ' as u8));
        assert_eq!(opts_parser(&b""[..]), Incomplete(Needed::Size(1)));

        for e in vec![b":E", b"%E"] {
            assert_eq!(opts_parser(&e[..]), Error(error_position!(ErrorKind::Alt, &e[..])));
        }
    }

    #[test]
    fn args_parser() {
        use super::args_parser;

        assert_eq!(args_parser(&br"abc"[..]), Done(&b"bc"[..], 'a' as u8));
        assert_eq!(args_parser(&br"\:abc"[..]), Done(&b":abc"[..], '\\' as u8));
        assert_eq!(args_parser(&br"\%abc"[..]), Done(&b"abc"[..], '%' as u8));
        assert_eq!(args_parser(&br"(abc"[..]), Done(&b"abc"[..], '(' as u8));
        assert_eq!(args_parser(&br"[abc"[..]), Done(&b"abc"[..], '[' as u8));
        assert_eq!(args_parser(&br" abc"[..]), Done(&b"abc"[..], ' ' as u8));
        assert_eq!(args_parser(&b""[..]), Incomplete(Needed::Size(1)));

        assert_eq!(args_parser(&b"%E"[..]), Error(error_position!(ErrorKind::Alt, &b"%E"[..])));
    }
}
<|endoftext|>


<commit_before><commit_msg>clone<commit_after><|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward { self.current_depth = self.current_depth + 1}
                    if command == Command::JumpBackward { self.current_depth = self.current_depth - 1}
                    vm.apply(command);
                    index = index + 1;
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, mut index: usize) -> usize {
        while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            index = index + 1;
        }
        return index;
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            return self.seek_forward(index)
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<commit_msg>Invoke handle_jump_forward if a '[' is seen<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.handle_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        self.current_depth = self.current_depth - 1
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, mut index: usize) -> usize {
        while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            index = index + 1;
        }
        return index;
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            return self.seek_forward(index)
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate toml_edit;

use serde_json::Map as JsonMap;
use serde_json::Value as Json;

use toml_edit::{Document, Item, Iter, Value};

fn pair_to_json((key, value): (&str, Item)) -> (String, Json) {
    fn typed_json(s: &str, json: Json) -> Json {
        let mut map = JsonMap::new();
        map.insert("type".to_owned(), Json::String(s.into()));
        map.insert("value".to_owned(), json);
        Json::Object(map)
    }
    fn value_to_json(value: &Value) -> Json {
        match *value {
            Value::String(ref s) => typed_json("string", Json::String(s.value().clone())),
            Value::Integer(ref i) => typed_json("integer", Json::String(format!("{}", i.value()))),
            Value::Float(ref f) => typed_json("float", Json::String(format!("{}", f.value()))),
            Value::Boolean(ref b) => typed_json("bool", Json::String(b.raw().into())),
            Value::DateTime(ref d) => typed_json("datetime", Json::String(d.raw().into())),
            Value::Array(ref a) => {
                let json = Json::Array(a.iter().map(value_to_json).collect::<Vec<_>>());
                typed_json("array", json)
            }
            Value::InlineTable(ref t) => {
                to_json(Box::new(t.iter().map(|(k, v)| (k, Item::Value(v.clone())))))
            }
        }
    }
    let json = match value {
        Item::Value(ref v) => value_to_json(v),
        Item::ArrayOfTables(ref arr) => Json::Array(
            arr.iter()
                .map(|t| to_json(iter_to_owned(t.iter())))
                .collect::<Vec<_>>(),
        ),
        Item::Table(ref table) => to_json(iter_to_owned(table.iter())),
        Item::None => Json::Null,
    };
    (key.to_owned(), json)
}

fn iter_to_owned(iter: Iter) -> OwnedIter {
    Box::new(iter.map(|(k, v)| (k, v.clone())))
}

type OwnedIter<'s> = Box<Iterator<Item = (&'s str, Item)> + 's>;

fn to_json(iter: OwnedIter) -> Json {
    Json::Object(iter.map(pair_to_json).collect())
}

fn run(json: &str, toml: &str) {
    let doc = toml.parse::<Document>();
    assert!(doc.is_ok());
    let doc = doc.unwrap();

    let json: Json = serde_json::from_str(json).unwrap();
    let toml_json = to_json(iter_to_owned(doc.iter()));
    // compare structure with jsons
    assert_eq!(json, toml_json);

    // check round-trip equality
    let toml = doc.to_string();
    let doc = toml.parse::<Document>();
    assert!(doc.is_ok());
    let doc = doc.unwrap();
    assert_eq!(doc.to_string(), toml);
}

macro_rules! t(
    ($name:ident, $json:expr, $toml:expr) => (
        #[test]
        fn $name() {
            run(include_str!($json),
                include_str!($toml));
        }
    )
);

#[test]
fn table_reordering() {
    let toml = r#"
[[bin]] # bin 1
[a.'b'.c.e]
[a]
[other.table]
[[bin]] # bin 2
[a.b.c.d]
[a."b".c]
[[bin]] # bin 3
"#;
    let expected = r#"
[[bin]] # bin 1
[[bin]] # bin 2
[[bin]] # bin 3
[a]
[a.'b'.c]
[a.'b'.c.e]
[a.'b'.c.d]
[other.table]
"#;
    let doc = toml.parse::<Document>();
    assert!(doc.is_ok());
    let doc = doc.unwrap();
    assert_eq!(doc.to_string(), expected);
}

t!(
    test_array_empty,
    "fixtures/valid/array-empty.json",
    "fixtures/valid/array-empty.toml"
);
t!(
    test_array_nopspaces,
    "fixtures/valid/array-nospaces.json",
    "fixtures/valid/array-nospaces.toml"
);
t!(
    test_arrays_hetergeneous,
    "fixtures/valid/arrays-hetergeneous.json",
    "fixtures/valid/arrays-hetergeneous.toml"
);
t!(
    test_arrays,
    "fixtures/valid/arrays.json",
    "fixtures/valid/arrays.toml"
);
t!(
    test_arrays_nested,
    "fixtures/valid/arrays-nested.json",
    "fixtures/valid/arrays-nested.toml"
);
t!(
    test_bool,
    "fixtures/valid/bool.json",
    "fixtures/valid/bool.toml"
);
t!(
    test_comment_at_eof2,
    "fixtures/valid/comments-at-eof2.json",
    "fixtures/valid/comments-at-eof2.toml"
);
t!(
    test_comment_at_eof,
    "fixtures/valid/comments-at-eof.json",
    "fixtures/valid/comments-at-eof.toml"
);
t!(
    test_comments_everywhere,
    "fixtures/valid/comments-everywhere.json",
    "fixtures/valid/comments-everywhere.toml"
);
t!(
    test_datetime,
    "fixtures/valid/datetime.json",
    "fixtures/valid/datetime.toml"
);
t!(
    test_empty,
    "fixtures/valid/empty.json",
    "fixtures/valid/empty.toml"
);
t!(
    test_example,
    "fixtures/valid/example.json",
    "fixtures/valid/example.toml"
);
t!(
    test_float_exponent,
    "fixtures/valid/float-exponent.json",
    "fixtures/valid/float-exponent.toml"
);
t!(
    test_float,
    "fixtures/valid/float.json",
    "fixtures/valid/float.toml"
);
t!(
    test_float_underscore,
    "fixtures/valid/float-underscore.json",
    "fixtures/valid/float-underscore.toml"
);
t!(
    test_implicit_and_explicit_after,
    "fixtures/valid/implicit-and-explicit-after.json",
    "fixtures/valid/implicit-and-explicit-after.toml"
);
t!(
    test_implicit_and_explicit_before,
    "fixtures/valid/implicit-and-explicit-before.json",
    "fixtures/valid/implicit-and-explicit-before.toml"
);
t!(
    test_implicit_groups,
    "fixtures/valid/implicit-groups.json",
    "fixtures/valid/implicit-groups.toml"
);
t!(
    test_inline_table,
    "fixtures/valid/inline-table.json",
    "fixtures/valid/inline-table.toml"
);
t!(
    test_integer,
    "fixtures/valid/integer.json",
    "fixtures/valid/integer.toml"
);
t!(
    test_integer_underscore,
    "fixtures/valid/integer-underscore.json",
    "fixtures/valid/integer-underscore.toml"
);
t!(
    test_keys_equal_nospace,
    "fixtures/valid/key-equals-nospace.json",
    "fixtures/valid/key-equals-nospace.toml"
);
t!(
    test_key_numeric,
    "fixtures/valid/key-numeric.json",
    "fixtures/valid/key-numeric.toml"
);
t!(
    test_key_space,
    "fixtures/valid/key-space.json",
    "fixtures/valid/key-space.toml"
);
t!(
    test_key_special_chars,
    "fixtures/valid/key-special-chars.json",
    "fixtures/valid/key-special-chars.toml"
);
t!(
    test_long_float,
    "fixtures/valid/long-float.json",
    "fixtures/valid/long-float.toml"
);
t!(
    test_long_integer,
    "fixtures/valid/long-integer.json",
    "fixtures/valid/long-integer.toml"
);
t!(
    test_multiline_string,
    "fixtures/valid/multiline-string.json",
    "fixtures/valid/multiline-string.toml"
);
t!(
    test_raw_multiline_string,
    "fixtures/valid/raw-multiline-string.json",
    "fixtures/valid/raw-multiline-string.toml"
);
t!(
    test_raw_string,
    "fixtures/valid/raw-string.json",
    "fixtures/valid/raw-string.toml"
);
t!(
    test_string_empty,
    "fixtures/valid/string-empty.json",
    "fixtures/valid/string-empty.toml"
);
t!(
    test_string_escapes,
    "fixtures/valid/string-escapes.json",
    "fixtures/valid/string-escapes.toml"
);
t!(
    test_string_nl,
    "fixtures/valid/string-nl.json",
    "fixtures/valid/string-nl.toml"
);
t!(
    test_string_simple,
    "fixtures/valid/string-simple.json",
    "fixtures/valid/string-simple.toml"
);
t!(
    test_string_with_pound,
    "fixtures/valid/string-with-pound.json",
    "fixtures/valid/string-with-pound.toml"
);
t!(
    test_table_array_implicit,
    "fixtures/valid/table-array-implicit.json",
    "fixtures/valid/table-array-implicit.toml"
);
t!(
    test_table_array_many,
    "fixtures/valid/table-array-many.json",
    "fixtures/valid/table-array-many.toml"
);
t!(
    test_table_array_nest,
    "fixtures/valid/table-array-nest.json",
    "fixtures/valid/table-array-nest.toml"
);
t!(
    test_array_one,
    "fixtures/valid/table-array-one.json",
    "fixtures/valid/table-array-one.toml"
);
t!(
    test_table_empty,
    "fixtures/valid/table-empty.json",
    "fixtures/valid/table-empty.toml"
);
t!(
    test_table_no_eol,
    "fixtures/valid/table-no-eol.json",
    "fixtures/valid/table-no-eol.toml"
);
t!(
    test_table_sub_empty,
    "fixtures/valid/table-sub-empty.json",
    "fixtures/valid/table-sub-empty.toml"
);
t!(
    test_whitespace,
    "fixtures/valid/table-whitespace.json",
    "fixtures/valid/table-whitespace.toml"
);
t!(
    test_table_with_literal_string,
    "fixtures/valid/table-with-literal-string.json",
    "fixtures/valid/table-with-literal-string.toml"
);
t!(
    test_table_with_poung,
    "fixtures/valid/table-with-pound.json",
    "fixtures/valid/table-with-pound.toml"
);
t!(
    test_table_with_single_quotes,
    "fixtures/valid/table-with-single-quotes.json",
    "fixtures/valid/table-with-single-quotes.toml"
);
t!(
    test_unicode_escape,
    "fixtures/valid/unicode-escape.json",
    "fixtures/valid/unicode-escape.toml"
);
t!(
    test_unicode_literal,
    "fixtures/valid/unicode-literal.json",
    "fixtures/valid/unicode-literal.toml"
);
t!(
    test_windows_path,
    "fixtures/valid/windows-path.json",
    "fixtures/valid/windows-path.toml"
);
<commit_msg>fix(tests): fix a warning<commit_after>extern crate serde_json;
extern crate toml_edit;

use serde_json::Map as JsonMap;
use serde_json::Value as Json;

use toml_edit::{Document, Item, Iter, Value};

fn pair_to_json((key, value): (&str, Item)) -> (String, Json) {
    fn typed_json(s: &str, json: Json) -> Json {
        let mut map = JsonMap::new();
        map.insert("type".to_owned(), Json::String(s.into()));
        map.insert("value".to_owned(), json);
        Json::Object(map)
    }
    fn value_to_json(value: &Value) -> Json {
        match *value {
            Value::String(ref s) => typed_json("string", Json::String(s.value().clone())),
            Value::Integer(ref i) => typed_json("integer", Json::String(format!("{}", i.value()))),
            Value::Float(ref f) => typed_json("float", Json::String(format!("{}", f.value()))),
            Value::Boolean(ref b) => typed_json("bool", Json::String(b.raw().into())),
            Value::DateTime(ref d) => typed_json("datetime", Json::String(d.raw().into())),
            Value::Array(ref a) => {
                let json = Json::Array(a.iter().map(value_to_json).collect::<Vec<_>>());
                typed_json("array", json)
            }
            Value::InlineTable(ref t) => {
                to_json(Box::new(t.iter().map(|(k, v)| (k, Item::Value(v.clone())))))
            }
        }
    }
    let json = match value {
        Item::Value(ref v) => value_to_json(v),
        Item::ArrayOfTables(ref arr) => Json::Array(
            arr.iter()
                .map(|t| to_json(iter_to_owned(t.iter())))
                .collect::<Vec<_>>(),
        ),
        Item::Table(ref table) => to_json(iter_to_owned(table.iter())),
        Item::None => Json::Null,
    };
    (key.to_owned(), json)
}

fn iter_to_owned(iter: Iter) -> OwnedIter {
    Box::new(iter.map(|(k, v)| (k, v.clone())))
}

type OwnedIter<'s> = Box<dyn Iterator<Item = (&'s str, Item)> + 's>;

fn to_json(iter: OwnedIter) -> Json {
    Json::Object(iter.map(pair_to_json).collect())
}

fn run(json: &str, toml: &str) {
    let doc = toml.parse::<Document>();
    assert!(doc.is_ok());
    let doc = doc.unwrap();

    let json: Json = serde_json::from_str(json).unwrap();
    let toml_json = to_json(iter_to_owned(doc.iter()));
    // compare structure with jsons
    assert_eq!(json, toml_json);

    // check round-trip equality
    let toml = doc.to_string();
    let doc = toml.parse::<Document>();
    assert!(doc.is_ok());
    let doc = doc.unwrap();
    assert_eq!(doc.to_string(), toml);
}

macro_rules! t(
    ($name:ident, $json:expr, $toml:expr) => (
        #[test]
        fn $name() {
            run(include_str!($json),
                include_str!($toml));
        }
    )
);

#[test]
fn table_reordering() {
    let toml = r#"
[[bin]] # bin 1
[a.'b'.c.e]
[a]
[other.table]
[[bin]] # bin 2
[a.b.c.d]
[a."b".c]
[[bin]] # bin 3
"#;
    let expected = r#"
[[bin]] # bin 1
[[bin]] # bin 2
[[bin]] # bin 3
[a]
[a.'b'.c]
[a.'b'.c.e]
[a.'b'.c.d]
[other.table]
"#;
    let doc = toml.parse::<Document>();
    assert!(doc.is_ok());
    let doc = doc.unwrap();
    assert_eq!(doc.to_string(), expected);
}

t!(
    test_array_empty,
    "fixtures/valid/array-empty.json",
    "fixtures/valid/array-empty.toml"
);
t!(
    test_array_nopspaces,
    "fixtures/valid/array-nospaces.json",
    "fixtures/valid/array-nospaces.toml"
);
t!(
    test_arrays_hetergeneous,
    "fixtures/valid/arrays-hetergeneous.json",
    "fixtures/valid/arrays-hetergeneous.toml"
);
t!(
    test_arrays,
    "fixtures/valid/arrays.json",
    "fixtures/valid/arrays.toml"
);
t!(
    test_arrays_nested,
    "fixtures/valid/arrays-nested.json",
    "fixtures/valid/arrays-nested.toml"
);
t!(
    test_bool,
    "fixtures/valid/bool.json",
    "fixtures/valid/bool.toml"
);
t!(
    test_comment_at_eof2,
    "fixtures/valid/comments-at-eof2.json",
    "fixtures/valid/comments-at-eof2.toml"
);
t!(
    test_comment_at_eof,
    "fixtures/valid/comments-at-eof.json",
    "fixtures/valid/comments-at-eof.toml"
);
t!(
    test_comments_everywhere,
    "fixtures/valid/comments-everywhere.json",
    "fixtures/valid/comments-everywhere.toml"
);
t!(
    test_datetime,
    "fixtures/valid/datetime.json",
    "fixtures/valid/datetime.toml"
);
t!(
    test_empty,
    "fixtures/valid/empty.json",
    "fixtures/valid/empty.toml"
);
t!(
    test_example,
    "fixtures/valid/example.json",
    "fixtures/valid/example.toml"
);
t!(
    test_float_exponent,
    "fixtures/valid/float-exponent.json",
    "fixtures/valid/float-exponent.toml"
);
t!(
    test_float,
    "fixtures/valid/float.json",
    "fixtures/valid/float.toml"
);
t!(
    test_float_underscore,
    "fixtures/valid/float-underscore.json",
    "fixtures/valid/float-underscore.toml"
);
t!(
    test_implicit_and_explicit_after,
    "fixtures/valid/implicit-and-explicit-after.json",
    "fixtures/valid/implicit-and-explicit-after.toml"
);
t!(
    test_implicit_and_explicit_before,
    "fixtures/valid/implicit-and-explicit-before.json",
    "fixtures/valid/implicit-and-explicit-before.toml"
);
t!(
    test_implicit_groups,
    "fixtures/valid/implicit-groups.json",
    "fixtures/valid/implicit-groups.toml"
);
t!(
    test_inline_table,
    "fixtures/valid/inline-table.json",
    "fixtures/valid/inline-table.toml"
);
t!(
    test_integer,
    "fixtures/valid/integer.json",
    "fixtures/valid/integer.toml"
);
t!(
    test_integer_underscore,
    "fixtures/valid/integer-underscore.json",
    "fixtures/valid/integer-underscore.toml"
);
t!(
    test_keys_equal_nospace,
    "fixtures/valid/key-equals-nospace.json",
    "fixtures/valid/key-equals-nospace.toml"
);
t!(
    test_key_numeric,
    "fixtures/valid/key-numeric.json",
    "fixtures/valid/key-numeric.toml"
);
t!(
    test_key_space,
    "fixtures/valid/key-space.json",
    "fixtures/valid/key-space.toml"
);
t!(
    test_key_special_chars,
    "fixtures/valid/key-special-chars.json",
    "fixtures/valid/key-special-chars.toml"
);
t!(
    test_long_float,
    "fixtures/valid/long-float.json",
    "fixtures/valid/long-float.toml"
);
t!(
    test_long_integer,
    "fixtures/valid/long-integer.json",
    "fixtures/valid/long-integer.toml"
);
t!(
    test_multiline_string,
    "fixtures/valid/multiline-string.json",
    "fixtures/valid/multiline-string.toml"
);
t!(
    test_raw_multiline_string,
    "fixtures/valid/raw-multiline-string.json",
    "fixtures/valid/raw-multiline-string.toml"
);
t!(
    test_raw_string,
    "fixtures/valid/raw-string.json",
    "fixtures/valid/raw-string.toml"
);
t!(
    test_string_empty,
    "fixtures/valid/string-empty.json",
    "fixtures/valid/string-empty.toml"
);
t!(
    test_string_escapes,
    "fixtures/valid/string-escapes.json",
    "fixtures/valid/string-escapes.toml"
);
t!(
    test_string_nl,
    "fixtures/valid/string-nl.json",
    "fixtures/valid/string-nl.toml"
);
t!(
    test_string_simple,
    "fixtures/valid/string-simple.json",
    "fixtures/valid/string-simple.toml"
);
t!(
    test_string_with_pound,
    "fixtures/valid/string-with-pound.json",
    "fixtures/valid/string-with-pound.toml"
);
t!(
    test_table_array_implicit,
    "fixtures/valid/table-array-implicit.json",
    "fixtures/valid/table-array-implicit.toml"
);
t!(
    test_table_array_many,
    "fixtures/valid/table-array-many.json",
    "fixtures/valid/table-array-many.toml"
);
t!(
    test_table_array_nest,
    "fixtures/valid/table-array-nest.json",
    "fixtures/valid/table-array-nest.toml"
);
t!(
    test_array_one,
    "fixtures/valid/table-array-one.json",
    "fixtures/valid/table-array-one.toml"
);
t!(
    test_table_empty,
    "fixtures/valid/table-empty.json",
    "fixtures/valid/table-empty.toml"
);
t!(
    test_table_no_eol,
    "fixtures/valid/table-no-eol.json",
    "fixtures/valid/table-no-eol.toml"
);
t!(
    test_table_sub_empty,
    "fixtures/valid/table-sub-empty.json",
    "fixtures/valid/table-sub-empty.toml"
);
t!(
    test_whitespace,
    "fixtures/valid/table-whitespace.json",
    "fixtures/valid/table-whitespace.toml"
);
t!(
    test_table_with_literal_string,
    "fixtures/valid/table-with-literal-string.json",
    "fixtures/valid/table-with-literal-string.toml"
);
t!(
    test_table_with_poung,
    "fixtures/valid/table-with-pound.json",
    "fixtures/valid/table-with-pound.toml"
);
t!(
    test_table_with_single_quotes,
    "fixtures/valid/table-with-single-quotes.json",
    "fixtures/valid/table-with-single-quotes.toml"
);
t!(
    test_unicode_escape,
    "fixtures/valid/unicode-escape.json",
    "fixtures/valid/unicode-escape.toml"
);
t!(
    test_unicode_literal,
    "fixtures/valid/unicode-literal.json",
    "fixtures/valid/unicode-literal.toml"
);
t!(
    test_windows_path,
    "fixtures/valid/windows-path.json",
    "fixtures/valid/windows-path.toml"
);
<|endoftext|>


<commit_before>extern crate noise_search;

use std::io::{Read, Write, BufReader};
use std::fs::{self, File};
use std::env;

use noise_search::repl::repl;

#[test]
fn test_repl() {
    // We load up tests scripts from repl-tests and evaluate them. The output should be idenitical
    // to the test script files. If not, then the test is failed and a new file is written with
    // .reject extension in the same directory where it can be investigated.

    // To update the test files with new command and output, simply edit/add commands and run
    // update-test-repl.sh script from the project root directory. Then examin or do a git diff to see
    // if the output is as expected.

    let mut test_dir = env::current_dir().unwrap();
    test_dir.push("repl-tests");
    let mut failures = 0;
    let mut total = 0;
    for entry in fs::read_dir(test_dir).unwrap() {
        let mut path = entry.unwrap().path();
        if path.extension().unwrap().to_str().unwrap() != "noise" {
            continue;
        }
        total += 1;
        let test_name = path.file_name().unwrap().to_str().unwrap().to_string();
        println!("About to run test {} ", test_name);
        let mut file = File::open(path.clone()).unwrap();
        let mut file_buffer = Vec::new();
        file.read_to_end(&mut file_buffer).unwrap();

        let mut test_result_buffer = Vec::new();
        let file = File::open(path.clone()).unwrap();
        repl(&mut BufReader::new(file), &mut test_result_buffer, true);

        if file_buffer != test_result_buffer {
            failures += 1;
            path.set_extension("reject");
            let reject = path.file_name().unwrap().to_str().unwrap().to_string();

            let mut file = File::create(path.clone()).unwrap();
            file.write_all(&test_result_buffer).unwrap();
            file.sync_all().unwrap();

            println!("Repl test {} failure. Failing output written to {} in repl-tests dir.",
                test_name, reject);
        } else {
            println!("{} successful", path.file_name().unwrap().to_str().unwrap().to_string());
        }
    }
    if total == 0 {
        panic!("No tests were run!");
    }
    if failures > 0 {
        panic!("Failed {} tests in repl-test out of {}", failures, total);
    }
}<commit_msg>Run repl tests ordered by last modified date<commit_after>extern crate noise_search;

use std::io::{Read, Write, BufReader};
use std::fs::{self, File};
use std::env;

use noise_search::repl::repl;

#[test]
fn test_repl() {
    // We load up tests scripts from repl-tests and evaluate them. The output should be idenitical
    // to the test script files. If not, then the test is failed and a new file is written with
    // .reject extension in the same directory where it can be investigated.

    // To update the test files with new command and output, simply edit/add commands and run
    // update-test-repl.sh script from the project root directory. Then examin or do a git diff to see
    // if the output is as expected.

    let mut test_dir = env::current_dir().unwrap();
    test_dir.push("repl-tests");
    let mut failures = 0;
    let mut total = 0;
    // Sort files by last modified date to make debugging easier
    let mut entries: Vec<_> = fs::read_dir(test_dir).unwrap().map(|r| r.unwrap()).collect();
    entries.sort_by_key(|entry| entry.metadata().unwrap().modified().unwrap());
    for entry in entries {
        let mut path = entry.path();
        if path.extension().unwrap().to_str().unwrap() != "noise" {
            continue;
        }
        total += 1;
        let test_name = path.file_name().unwrap().to_str().unwrap().to_string();
        println!("About to run test {} ", test_name);
        let mut file = File::open(path.clone()).unwrap();
        let mut file_buffer = Vec::new();
        file.read_to_end(&mut file_buffer).unwrap();

        let mut test_result_buffer = Vec::new();
        let file = File::open(path.clone()).unwrap();
        repl(&mut BufReader::new(file), &mut test_result_buffer, true);

        if file_buffer != test_result_buffer {
            failures += 1;
            path.set_extension("reject");
            let reject = path.file_name().unwrap().to_str().unwrap().to_string();

            let mut file = File::create(path.clone()).unwrap();
            file.write_all(&test_result_buffer).unwrap();
            file.sync_all().unwrap();

            println!("Repl test {} failure. Failing output written to {} in repl-tests dir.",
                test_name, reject);
        } else {
            println!("{} successful", path.file_name().unwrap().to_str().unwrap().to_string());
        }
    }
    if total == 0 {
        panic!("No tests were run!");
    }
    if failures > 0 {
        panic!("Failed {} tests in repl-test out of {}", failures, total);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Formatter, Error};
use std::process::Command;

extern crate log;
use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

pub use cli::CliConfig;
pub use configuration::Configuration as Cfg;

use storage::Store;

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

    pub fn init(config: &CliConfig) -> Result<(), SetLoggerError> {
        let lvl = if config.is_debugging() {
            LogLevelFilter::Debug
        } else if config.is_verbose() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with: {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
    }

}

impl log::Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}]: {}", record.level(), record.args());
        }
    }
}

/**
 * Runtime object, represents a single interface to both the CLI configuration and the
 * configuration file. Also carries the store object around and is basically an object which
 * contains everything which is required to run a command/module.
 */
pub struct Runtime<'a> {
    pub config : CliConfig<'a>,
    pub configuration : Cfg,
    pub store : Store,
}

impl<'a> Runtime<'a> {

    pub fn new(cfg: Cfg, config : CliConfig<'a>) -> Runtime<'a> {
        let sp = config.store_path().unwrap_or(cfg.store_path());
        Runtime {
            config: config,
            configuration: cfg,
            store: Store::new(sp),
        }
    }

    /**
     * Check whether we run verbose
     */
    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose()
    }

    /**
     * Check whether we run in debugging
     */
    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging()
    }

    /**
     * Get the store path we are currently using
     */
    pub fn store_path(&self) -> String {
        self.config.store_path().unwrap_or(self.configuration.store_path())
    }

    /**
     * Get the store object
     */
    pub fn store(&self) -> &Store {
        &self.store
    }

    /**
     * Get the runtime path we are currently using
     */
    pub fn get_rtp(&self) -> String {
        if let Some(rtp) = self.config.get_rtp() {
            rtp
        } else {
            self.configuration.get_rtp()
        }
    }

    pub fn editor(&self) -> Command {
        use std::env::var;

        let (editor, args) : (String, String) = {
            if let Some(editor) = self.config.editor() {
                (editor, self.config.editor_opts())
            } else if let Some(editor) = self.configuration.editor() {
                (editor, self.configuration.editor_opts())
            } else if let Ok(editor) = var("EDITOR") {
                (editor, String::from(""))
            } else {
                (String::from("vim"), String::from(""))
            }
        };

        let mut e = Command::new(editor);
        for arg in args.split(" ") {
            e.arg(arg);
        }
        e
    }

}

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

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Runtime (verbose: {}, debugging: {}, rtp: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp())
    }

}

<commit_msg>Add runtime wrapper for reporting mode<commit_after>use std::fmt::{Debug, Formatter, Error};
use std::process::Command;

extern crate log;
use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

pub use cli::CliConfig;
pub use configuration::Configuration as Cfg;

use storage::Store;

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

    pub fn init(config: &CliConfig) -> Result<(), SetLoggerError> {
        let lvl = if config.is_debugging() {
            LogLevelFilter::Debug
        } else if config.is_verbose() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with: {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
    }

}

impl log::Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}]: {}", record.level(), record.args());
        }
    }
}

/**
 * Runtime object, represents a single interface to both the CLI configuration and the
 * configuration file. Also carries the store object around and is basically an object which
 * contains everything which is required to run a command/module.
 */
pub struct Runtime<'a> {
    pub config : CliConfig<'a>,
    pub configuration : Cfg,
    pub store : Store,
}

impl<'a> Runtime<'a> {

    pub fn new(cfg: Cfg, config : CliConfig<'a>) -> Runtime<'a> {
        let sp = config.store_path().unwrap_or(cfg.store_path());
        Runtime {
            config: config,
            configuration: cfg,
            store: Store::new(sp),
        }
    }

    /**
     * Check whether we run verbose
     */
    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose()
    }

    /**
     * Check whether we run in debugging
     */
    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging()
    }

    /**
     * Get the store path we are currently using
     */
    pub fn store_path(&self) -> String {
        self.config.store_path().unwrap_or(self.configuration.store_path())
    }

    /**
     * Get the store object
     */
    pub fn store(&self) -> &Store {
        &self.store
    }

    /**
     * Get the runtime path we are currently using
     */
    pub fn get_rtp(&self) -> String {
        if let Some(rtp) = self.config.get_rtp() {
            rtp
        } else {
            self.configuration.get_rtp()
        }
    }

    pub fn editor(&self) -> Command {
        use std::env::var;

        let (editor, args) : (String, String) = {
            if let Some(editor) = self.config.editor() {
                (editor, self.config.editor_opts())
            } else if let Some(editor) = self.configuration.editor() {
                (editor, self.configuration.editor_opts())
            } else if let Ok(editor) = var("EDITOR") {
                (editor, String::from(""))
            } else {
                (String::from("vim"), String::from(""))
            }
        };

        let mut e = Command::new(editor);
        for arg in args.split(" ") {
            e.arg(arg);
        }
        e
    }

    pub fn report_exit(&self) -> bool {
        self.config.report_exit() || self.configuration.report_exit()
    }

}

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

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Runtime (verbose: {}, debugging: {}, rtp: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp())
    }

}

<|endoftext|>


<commit_before>extern crate libc;
extern crate "termbox-sys" as termbox;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[deriving(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[deriving(Copy)]
pub enum Color {
    Default,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

#[deriving(Copy)]
pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline,
    Reverse
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => {
            return Event::KeyEvent(ev.emod, ev.key, ev.ch);
        },
        2 => {
            return Event::ResizeEvent(ev.w, ev.h);
        },
        _ => { panic!("Unknown event"); }
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Color::Default => 0x00,
        Color::Black   => 0x01,
        Color::Red     => 0x02,
        Color::Green   => 0x03,
        Color::Yellow  => 0x04,
        Color::Blue    => 0x05,
        Color::Magenta => 0x06,
        Color::Cyan    => 0x07,
        Color::White   => 0x08,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Style::Normal         => 0x0000,
        Style::Bold           => 0x0100,
        Style::Underline      => 0x0200,
        Style::BoldUnderline  => 0x0300,
        Style::Reverse        => 0x0400,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: String) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.as_slice().chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        return unpack_event(rc, &ev);
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        return unpack_event(rc, &ev);
    }
}
<commit_msg>Accept `&str` instead of `String` in `rustbox::print`.<commit_after>extern crate libc;
extern crate "termbox-sys" as termbox;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[deriving(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[deriving(Copy)]
pub enum Color {
    Default,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

#[deriving(Copy)]
pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline,
    Reverse
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => {
            return Event::KeyEvent(ev.emod, ev.key, ev.ch);
        },
        2 => {
            return Event::ResizeEvent(ev.w, ev.h);
        },
        _ => { panic!("Unknown event"); }
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Color::Default => 0x00,
        Color::Black   => 0x01,
        Color::Red     => 0x02,
        Color::Green   => 0x03,
        Color::Yellow  => 0x04,
        Color::Blue    => 0x05,
        Color::Magenta => 0x06,
        Color::Cyan    => 0x07,
        Color::White   => 0x08,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Style::Normal         => 0x0000,
        Style::Bold           => 0x0100,
        Style::Underline      => 0x0200,
        Style::BoldUnderline  => 0x0300,
        Style::Reverse        => 0x0400,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: &str) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        return unpack_event(rc, &ev);
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        return unpack_event(rc, &ev);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// 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.

use vector::{distance3, dot3, lerp3, Vec3f};
use range::InclusiveRange;

pub type Rangef = InclusiveRange<f32>;

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Get vector from start to end (not normalized)
    pub fn to_vec3f(&self) -> Vec3f {
        self.end - self.start
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Treat the range's start and end as parametric coords. Use
    /// `point_from_parametric` to interpolate the range into a new
    /// segment.
    pub fn segment_from_parametric_range(&self, r: Rangef) -> Segment3f {
        Segment3f::new(&self.point_from_parametric(r.min),
                       &self.point_from_parametric(r.max))
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

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

    #[test]
    fn test_to_vec3f() {
        use vector::vec3f;
        assert_eq!(Segment3f::new(&vec3f(0, 0, 0),
                                  &vec3f(2, 3, 4)).to_vec3f(),
                   vec3f(2, 3, 4));

    }

    #[test]
    fn test_segment_length() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(0, 0, 0),
                               &vec3f(0, 0, 9));
        assert_eq!(s.length(), 9.0);
    }

    #[test]
    fn test_segment_distance_conversion() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(0, 1, 0),
                               &vec3f(0, 7, 0));

        let inputs = [
            (0.0f32, 0.0f32),
            (6.0, 1.0),
            (12.0, 2.0),
            (-3.0, -0.5)];

        for &(distance, delta) in inputs.iter() {
            assert_eq!(s.distance_to_parametric_delta(distance), delta);
            assert_eq!(s.distance_from_parametric_delta(delta), distance);
        }
    }

    #[test]
    fn test_point_from_parametric() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(0, 0, -1),
                               &vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
        assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
    }

    #[test]
    fn test_segment_from_parametric_range() {
        use vector::vec3f;
        fn make_seg(a: u32, b: u32) -> Segment3f {
            Segment3f::new(&vec3f(a, 0, 0), &vec3f(b, 0, 0))
        }
        let s = make_seg(0, 4);
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.0, 1.0)),
                   make_seg(0, 4));
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.25, 0.75)),
                   make_seg(1, 3));
    }

    #[test]
    fn test_segment_closest_point_to_point() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(2, 0, 0),
                               &vec3f(3, 0, 0));
        assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
                   (0.0, vec3f(2, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
                   (1.0, vec3f(3, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
                   (0.5, vec3f(2.5, 0, 0)));
    }
}
<commit_msg>Update comment<commit_after>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// 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.

use vector::{distance3, dot3, lerp3, Vec3f};
use range::InclusiveRange;

pub type Rangef = InclusiveRange<f32>;

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Get vector from start to end (not normalized)
    pub fn to_vec3f(&self) -> Vec3f {
        self.end - self.start
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Treat the range's start and end as parametric coords. Use
    /// `point_from_parametric` to interpolate the range into a new
    /// segment. The output segment is not clamped.
    pub fn segment_from_parametric_range(&self, r: Rangef) -> Segment3f {
        Segment3f::new(&self.point_from_parametric(r.min),
                       &self.point_from_parametric(r.max))
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

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

    #[test]
    fn test_to_vec3f() {
        use vector::vec3f;
        assert_eq!(Segment3f::new(&vec3f(0, 0, 0),
                                  &vec3f(2, 3, 4)).to_vec3f(),
                   vec3f(2, 3, 4));

    }

    #[test]
    fn test_segment_length() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(0, 0, 0),
                               &vec3f(0, 0, 9));
        assert_eq!(s.length(), 9.0);
    }

    #[test]
    fn test_segment_distance_conversion() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(0, 1, 0),
                               &vec3f(0, 7, 0));

        let inputs = [
            (0.0f32, 0.0f32),
            (6.0, 1.0),
            (12.0, 2.0),
            (-3.0, -0.5)];

        for &(distance, delta) in inputs.iter() {
            assert_eq!(s.distance_to_parametric_delta(distance), delta);
            assert_eq!(s.distance_from_parametric_delta(delta), distance);
        }
    }

    #[test]
    fn test_point_from_parametric() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(0, 0, -1),
                               &vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
        assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
    }

    #[test]
    fn test_segment_from_parametric_range() {
        use vector::vec3f;
        fn make_seg(a: u32, b: u32) -> Segment3f {
            Segment3f::new(&vec3f(a, 0, 0), &vec3f(b, 0, 0))
        }
        let s = make_seg(0, 4);
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.0, 1.0)),
                   make_seg(0, 4));
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.25, 0.75)),
                   make_seg(1, 3));
    }

    #[test]
    fn test_segment_closest_point_to_point() {
        use vector::vec3f;
        let s = Segment3f::new(&vec3f(2, 0, 0),
                               &vec3f(3, 0, 0));
        assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
                   (0.0, vec3f(2, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
                   (1.0, vec3f(3, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
                   (0.5, vec3f(2.5, 0, 0)));
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::marker::PhantomData;

use actix_net::codec::Framed;
use actix_net::service::{NewService, Service};
use futures::future::{ok, Either, FutureResult};
use futures::{Async, AsyncSink, Future, Poll, Sink};
use tokio_io::AsyncWrite;

use error::ResponseError;
use h1::{Codec, Message};
use response::Response;

pub struct SendError<T, R, E>(PhantomData<(T, R, E)>);

impl<T, R, E> Default for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    fn default() -> Self {
        SendError(PhantomData)
    }
}

impl<T, R, E> NewService for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type InitError = ();
    type Service = SendError<T, R, E>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendError(PhantomData))
    }
}

impl<T, R, E> Service for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type Future = Either<FutureResult<R, (E, Framed<T, Codec>)>, SendErrorFut<T, R, E>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, req: Self::Request) -> Self::Future {
        match req {
            Ok(r) => Either::A(ok(r)),
            Err((e, framed)) => {
                let mut resp = e.error_response();
                resp.set_body(format!("{}", e));
                Either::B(SendErrorFut {
                    framed: Some(framed),
                    res: Some(resp.into()),
                    err: Some(e),
                    _t: PhantomData,
                })
            }
        }
    }
}

pub struct SendErrorFut<T, R, E> {
    res: Option<Message<Response>>,
    framed: Option<Framed<T, Codec>>,
    err: Option<E>,
    _t: PhantomData<R>,
}

impl<T, R, E> Future for SendErrorFut<T, R, E>
where
    E: ResponseError,
    T: AsyncWrite,
{
    type Item = R;
    type Error = (E, Framed<T, Codec>);

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if let Some(res) = self.res.take() {
            match self.framed.as_mut().unwrap().start_send(res) {
                Ok(AsyncSink::Ready) => (),
                Ok(AsyncSink::NotReady(res)) => {
                    self.res = Some(res);
                    return Ok(Async::NotReady);
                }
                Err(_) => {
                    return Err((self.err.take().unwrap(), self.framed.take().unwrap()))
                }
            }
        }
        match self.framed.as_mut().unwrap().poll_complete() {
            Ok(Async::Ready(_)) => {
                Err((self.err.take().unwrap(), self.framed.take().unwrap()))
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(_) => Err((self.err.take().unwrap(), self.framed.take().unwrap())),
        }
    }
}

pub struct SendResponse<T>(PhantomData<(T,)>);

impl<T> Default for SendResponse<T>
where
    T: AsyncWrite,
{
    fn default() -> Self {
        SendResponse(PhantomData)
    }
}

impl<T> NewService for SendResponse<T>
where
    T: AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = io::Error;
    type InitError = ();
    type Service = SendResponse<T>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendResponse(PhantomData))
    }
}

impl<T> Service for SendResponse<T>
where
    T: AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = io::Error;
    type Future = SendResponseFut<T>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, (res, framed): Self::Request) -> Self::Future {
        SendResponseFut {
            res: Some(Message::Item(res)),
            framed: Some(framed),
        }
    }
}

pub struct SendResponseFut<T> {
    res: Option<Message<Response>>,
    framed: Option<Framed<T, Codec>>,
}

impl<T> Future for SendResponseFut<T>
where
    T: AsyncWrite,
{
    type Item = Framed<T, Codec>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if let Some(res) = self.res.take() {
            match self.framed.as_mut().unwrap().start_send(res)? {
                AsyncSink::Ready => (),
                AsyncSink::NotReady(res) => {
                    self.res = Some(res);
                    return Ok(Async::NotReady);
                }
            }
        }
        match self.framed.as_mut().unwrap().poll_complete()? {
            Async::Ready(_) => Ok(Async::Ready(self.framed.take().unwrap())),
            Async::NotReady => Ok(Async::NotReady),
        }
    }
}
<commit_msg>SendResponse service sends body as well<commit_after>use std::marker::PhantomData;

use actix_net::codec::Framed;
use actix_net::service::{NewService, Service};
use futures::future::{ok, Either, FutureResult};
use futures::{Async, AsyncSink, Future, Poll, Sink};
use tokio_io::{AsyncRead, AsyncWrite};

use body::Body;
use error::{Error, ResponseError};
use h1::{Codec, Message};
use response::Response;

pub struct SendError<T, R, E>(PhantomData<(T, R, E)>);

impl<T, R, E> Default for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    fn default() -> Self {
        SendError(PhantomData)
    }
}

impl<T, R, E> NewService for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type InitError = ();
    type Service = SendError<T, R, E>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendError(PhantomData))
    }
}

impl<T, R, E> Service for SendError<T, R, E>
where
    T: AsyncWrite,
    E: ResponseError,
{
    type Request = Result<R, (E, Framed<T, Codec>)>;
    type Response = R;
    type Error = (E, Framed<T, Codec>);
    type Future = Either<FutureResult<R, (E, Framed<T, Codec>)>, SendErrorFut<T, R, E>>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, req: Self::Request) -> Self::Future {
        match req {
            Ok(r) => Either::A(ok(r)),
            Err((e, framed)) => {
                let mut resp = e.error_response();
                resp.set_body(format!("{}", e));
                Either::B(SendErrorFut {
                    framed: Some(framed),
                    res: Some(resp.into()),
                    err: Some(e),
                    _t: PhantomData,
                })
            }
        }
    }
}

pub struct SendErrorFut<T, R, E> {
    res: Option<Message<Response>>,
    framed: Option<Framed<T, Codec>>,
    err: Option<E>,
    _t: PhantomData<R>,
}

impl<T, R, E> Future for SendErrorFut<T, R, E>
where
    E: ResponseError,
    T: AsyncWrite,
{
    type Item = R;
    type Error = (E, Framed<T, Codec>);

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if let Some(res) = self.res.take() {
            match self.framed.as_mut().unwrap().start_send(res) {
                Ok(AsyncSink::Ready) => (),
                Ok(AsyncSink::NotReady(res)) => {
                    self.res = Some(res);
                    return Ok(Async::NotReady);
                }
                Err(_) => {
                    return Err((self.err.take().unwrap(), self.framed.take().unwrap()))
                }
            }
        }
        match self.framed.as_mut().unwrap().poll_complete() {
            Ok(Async::Ready(_)) => {
                Err((self.err.take().unwrap(), self.framed.take().unwrap()))
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(_) => Err((self.err.take().unwrap(), self.framed.take().unwrap())),
        }
    }
}

pub struct SendResponse<T>(PhantomData<(T,)>);

impl<T> Default for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    fn default() -> Self {
        SendResponse(PhantomData)
    }
}

impl<T> SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    pub fn send(
        mut framed: Framed<T, Codec>,
        mut res: Response,
    ) -> impl Future<Item = Framed<T, Codec>, Error = Error> {
        // init codec
        framed.get_codec_mut().prepare_te(&mut res);

        // extract body from response
        let body = res.replace_body(Body::Empty);

        // write response
        SendResponseFut {
            res: Some(Message::Item(res)),
            body: Some(body),
            framed: Some(framed),
        }
    }
}

impl<T> NewService for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = Error;
    type InitError = ();
    type Service = SendResponse<T>;
    type Future = FutureResult<Self::Service, Self::InitError>;

    fn new_service(&self) -> Self::Future {
        ok(SendResponse(PhantomData))
    }
}

impl<T> Service for SendResponse<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Request = (Response, Framed<T, Codec>);
    type Response = Framed<T, Codec>;
    type Error = Error;
    type Future = SendResponseFut<T>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        Ok(Async::Ready(()))
    }

    fn call(&mut self, (mut res, mut framed): Self::Request) -> Self::Future {
        framed.get_codec_mut().prepare_te(&mut res);
        let body = res.replace_body(Body::Empty);
        SendResponseFut {
            res: Some(Message::Item(res)),
            body: Some(body),
            framed: Some(framed),
        }
    }
}

pub struct SendResponseFut<T> {
    res: Option<Message<Response>>,
    body: Option<Body>,
    framed: Option<Framed<T, Codec>>,
}

impl<T> Future for SendResponseFut<T>
where
    T: AsyncRead + AsyncWrite,
{
    type Item = Framed<T, Codec>;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // send response
        if self.res.is_some() {
            let framed = self.framed.as_mut().unwrap();
            if !framed.is_write_buf_full() {
                if let Some(res) = self.res.take() {
                    println!("SEND RESP: {:?}", res);
                    framed.force_send(res)?;
                }
            }
        }

        // send body
        if self.res.is_none() && self.body.is_some() {
            let framed = self.framed.as_mut().unwrap();
            if !framed.is_write_buf_full() {
                let body = self.body.take().unwrap();
                match body {
                    Body::Empty => (),
                    Body::Streaming(mut stream) => loop {
                        match stream.poll()? {
                            Async::Ready(item) => {
                                let done = item.is_none();
                                framed.force_send(Message::Chunk(item.into()))?;
                                if !done {
                                    if !framed.is_write_buf_full() {
                                        continue;
                                    } else {
                                        self.body = Some(Body::Streaming(stream));
                                        break;
                                    }
                                }
                            }
                            Async::NotReady => {
                                self.body = Some(Body::Streaming(stream));
                                break;
                            }
                        }
                    },
                    Body::Binary(mut bin) => {
                        framed.force_send(Message::Chunk(Some(bin.take())))?;
                        framed.force_send(Message::Chunk(None))?;
                    }
                }
            }
        }

        // flush
        match self.framed.as_mut().unwrap().poll_complete()? {
            Async::Ready(_) => if self.res.is_some() || self.body.is_some() {
                return self.poll();
            },
            Async::NotReady => return Ok(Async::NotReady),
        }

        Ok(Async::Ready(self.framed.take().unwrap()))
    }
}
<|endoftext|>