<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Rule {
    pub name: String,
    pub ty: RuleType,
    pub expr: Expr
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RuleType {
    Normal,
    Silent,
    Atomic,
    CompoundAtomic,
    NonAtomic
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Expr {
    /// Matches an exact string, e.g. `"a"`
    Str(String),
    /// Matches an exact string, case insensitively (ASCII only), e.g. `^"a"`
    Insens(String),
    /// Matches one character in the range, e.g. `'a'..'z'`
    Range(String, String),
    /// Matches the rule with the given name, e.g. `a`
    Ident(String),
    /// Matches a custom part of the stack
    PeekSlice(i32, Option<i32>),
    /// Positive lookahead; matches expression without making progress, e.g. `&e`
    PosPred(Box<Expr>),
    /// Negative lookahead; matches if expression doesn't match, without making progress, e.g. `!e`
    NegPred(Box<Expr>),
    /// Matches a sequence of two expressions, e.g. `e1 ~ e2`
    Seq(Box<Expr>, Box<Expr>),
    /// Matches either of two expressions, e.g. `e1 | e2`
    Choice(Box<Expr>, Box<Expr>),
    /// Optionally matches an expression, e.g. `e?`
    Opt(Box<Expr>),
    /// Matches an expression zero or more times, e.g. `e*`
    Rep(Box<Expr>),
    /// Matches an expression one or more times, e.g. `e+`
    RepOnce(Box<Expr>),
    /// Matches an expression an exact number of times, e.g. `e{n}`
    RepExact(Box<Expr>, u32),
    /// Matches an expression at least a number of times, e.g. `e{n,}`
    RepMin(Box<Expr>, u32),
    /// Matches an expression at most a number of times, e.g. `e{,n}`
    RepMax(Box<Expr>, u32),
    /// Matches an expression a number of times within a range, e.g. `e{m, n}`
    RepMinMax(Box<Expr>, u32, u32),
    /// Continues to match expressions until one of the strings in the `Vec` is found
    Skip(Vec<String>),
    /// Matches an expression and pushes it to the stack, e.g. `push(e)`
    Push(Box<Expr>)
}

impl Expr {
    pub fn iter_top_down(&self) -> ExprTopDownIterator {
        ExprTopDownIterator::new(self)
    }

    pub fn map_top_down<F>(self, mut f: F) -> Expr
    where
        F: FnMut(Expr) -> Expr
    {
        fn map_internal<F>(expr: Expr, f: &mut F) -> Expr
        where
            F: FnMut(Expr) -> Expr
        {
            let expr = f(expr);

            match expr {
                // TODO: Use box syntax when it gets stabilized.
                Expr::PosPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepOnce(mapped)
                }
                Expr::RepExact(expr, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepExact(mapped, max)
                }
                Expr::RepMin(expr, num) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMin(mapped, num)
                }
                Expr::RepMax(expr, num) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMax(mapped, num)
                }
                Expr::RepMinMax(expr, min, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMinMax(mapped, min, max)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Push(mapped)
                }
                expr => expr
            }
        }

        map_internal(self, &mut f)
    }

    pub fn map_bottom_up<F>(self, mut f: F) -> Expr
    where
        F: FnMut(Expr) -> Expr
    {
        fn map_internal<F>(expr: Expr, f: &mut F) -> Expr
        where
            F: FnMut(Expr) -> Expr
        {
            let mapped = match expr {
                Expr::PosPred(expr) => {
                    // TODO: Use box syntax when it gets stabilized.
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepOnce(mapped)
                }
                Expr::RepExact(expr, num) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepExact(mapped, num)
                }
                Expr::RepMin(expr, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMin(mapped, max)
                }
                Expr::RepMax(expr, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMax(mapped, max)
                }
                Expr::RepMinMax(expr, min, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMinMax(mapped, min, max)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Push(mapped)
                }
                expr => expr
            };

            f(mapped)
        }

        map_internal(self, &mut f)
    }
}

pub struct ExprTopDownIterator {
    current: Option<Expr>,
    next: Option<Expr>,
    right_branches: Vec<Expr>
}

impl ExprTopDownIterator {
    pub fn new(expr: &Expr) -> Self {
        let mut iter = ExprTopDownIterator {
            current: None,
            next: None,
            right_branches: vec![]
        };
        iter.iterate_expr(expr.clone());
        iter
    }

    fn iterate_expr(&mut self, expr: Expr) {
        self.current = Some(expr.clone());
        match expr {
            Expr::Seq(lhs, rhs) => {
                self.right_branches.push(*rhs);
                self.next = Some(*lhs);
            }
            Expr::Choice(lhs, rhs) => {
                self.right_branches.push(*rhs);
                self.next = Some(*lhs);
            }
            Expr::PosPred(expr)
            | Expr::NegPred(expr)
            | Expr::Rep(expr)
            | Expr::RepOnce(expr)
            | Expr::RepExact(expr, _)
            | Expr::RepMin(expr, _)
            | Expr::RepMax(expr, _)
            | Expr::RepMinMax(expr, ..)
            | Expr::Opt(expr)
            | Expr::Push(expr) => {
                self.next = Some(*expr);
            }
            _ => {
                self.next = None;
            }
        }
    }
}

impl Iterator for ExprTopDownIterator {
    type Item = Expr;

    fn next(&mut self) -> Option<Self::Item> {
        let result = self.current.take();

        if let Some(expr) = self.next.take() {
            self.iterate_expr(expr);
        } else if let Some(expr) = self.right_branches.pop() {
            self.iterate_expr(expr);
        }

        result
    }
}

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

    #[test]
    fn top_down_iterator() {
        let expr = Expr::Choice(
            Box::new(Expr::Str(String::from("a"))),
            Box::new(Expr::Str(String::from("b")))
        );
        let mut top_down = expr.clone().iter_top_down();
        assert_eq!(top_down.next(), Some(expr));
        assert_eq!(top_down.next(), Some(Expr::Str(String::from("a"))));
        assert_eq!(top_down.next(), Some(Expr::Str(String::from("b"))));
        assert_eq!(top_down.next(), None);
    }

    #[test]
    fn identity() {
        let expr = Expr::Choice(
            Box::new(Expr::Seq(
                Box::new(Expr::Ident("a".to_owned())),
                Box::new(Expr::Str("b".to_owned()))
            )),
            Box::new(Expr::PosPred(Box::new(Expr::NegPred(Box::new(Expr::Rep(
                Box::new(Expr::RepOnce(Box::new(Expr::Opt(Box::new(Expr::Choice(
                    Box::new(Expr::Insens("c".to_owned())),
                    Box::new(Expr::Push(Box::new(Expr::Range(
                        "'d'".to_owned(),
                        "'e'".to_owned()
                    ))))
                ))))))
            ))))))
        );

        assert_eq!(
            expr.clone()
                .map_bottom_up(|expr| expr)
                .map_top_down(|expr| expr),
            expr
        );
    }
}
<commit_msg>Clarified peek_slice doc<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Rule {
    pub name: String,
    pub ty: RuleType,
    pub expr: Expr
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RuleType {
    Normal,
    Silent,
    Atomic,
    CompoundAtomic,
    NonAtomic
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Expr {
    /// Matches an exact string, e.g. `"a"`
    Str(String),
    /// Matches an exact string, case insensitively (ASCII only), e.g. `^"a"`
    Insens(String),
    /// Matches one character in the range, e.g. `'a'..'z'`
    Range(String, String),
    /// Matches the rule with the given name, e.g. `a`
    Ident(String),
    /// Matches a custom part of the stack, e.g. `PEEK[..]`
    PeekSlice(i32, Option<i32>),
    /// Positive lookahead; matches expression without making progress, e.g. `&e`
    PosPred(Box<Expr>),
    /// Negative lookahead; matches if expression doesn't match, without making progress, e.g. `!e`
    NegPred(Box<Expr>),
    /// Matches a sequence of two expressions, e.g. `e1 ~ e2`
    Seq(Box<Expr>, Box<Expr>),
    /// Matches either of two expressions, e.g. `e1 | e2`
    Choice(Box<Expr>, Box<Expr>),
    /// Optionally matches an expression, e.g. `e?`
    Opt(Box<Expr>),
    /// Matches an expression zero or more times, e.g. `e*`
    Rep(Box<Expr>),
    /// Matches an expression one or more times, e.g. `e+`
    RepOnce(Box<Expr>),
    /// Matches an expression an exact number of times, e.g. `e{n}`
    RepExact(Box<Expr>, u32),
    /// Matches an expression at least a number of times, e.g. `e{n,}`
    RepMin(Box<Expr>, u32),
    /// Matches an expression at most a number of times, e.g. `e{,n}`
    RepMax(Box<Expr>, u32),
    /// Matches an expression a number of times within a range, e.g. `e{m, n}`
    RepMinMax(Box<Expr>, u32, u32),
    /// Continues to match expressions until one of the strings in the `Vec` is found
    Skip(Vec<String>),
    /// Matches an expression and pushes it to the stack, e.g. `push(e)`
    Push(Box<Expr>)
}

impl Expr {
    pub fn iter_top_down(&self) -> ExprTopDownIterator {
        ExprTopDownIterator::new(self)
    }

    pub fn map_top_down<F>(self, mut f: F) -> Expr
    where
        F: FnMut(Expr) -> Expr
    {
        fn map_internal<F>(expr: Expr, f: &mut F) -> Expr
        where
            F: FnMut(Expr) -> Expr
        {
            let expr = f(expr);

            match expr {
                // TODO: Use box syntax when it gets stabilized.
                Expr::PosPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepOnce(mapped)
                }
                Expr::RepExact(expr, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepExact(mapped, max)
                }
                Expr::RepMin(expr, num) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMin(mapped, num)
                }
                Expr::RepMax(expr, num) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMax(mapped, num)
                }
                Expr::RepMinMax(expr, min, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMinMax(mapped, min, max)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Push(mapped)
                }
                expr => expr
            }
        }

        map_internal(self, &mut f)
    }

    pub fn map_bottom_up<F>(self, mut f: F) -> Expr
    where
        F: FnMut(Expr) -> Expr
    {
        fn map_internal<F>(expr: Expr, f: &mut F) -> Expr
        where
            F: FnMut(Expr) -> Expr
        {
            let mapped = match expr {
                Expr::PosPred(expr) => {
                    // TODO: Use box syntax when it gets stabilized.
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepOnce(mapped)
                }
                Expr::RepExact(expr, num) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepExact(mapped, num)
                }
                Expr::RepMin(expr, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMin(mapped, max)
                }
                Expr::RepMax(expr, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMax(mapped, max)
                }
                Expr::RepMinMax(expr, min, max) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepMinMax(mapped, min, max)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Push(mapped)
                }
                expr => expr
            };

            f(mapped)
        }

        map_internal(self, &mut f)
    }
}

pub struct ExprTopDownIterator {
    current: Option<Expr>,
    next: Option<Expr>,
    right_branches: Vec<Expr>
}

impl ExprTopDownIterator {
    pub fn new(expr: &Expr) -> Self {
        let mut iter = ExprTopDownIterator {
            current: None,
            next: None,
            right_branches: vec![]
        };
        iter.iterate_expr(expr.clone());
        iter
    }

    fn iterate_expr(&mut self, expr: Expr) {
        self.current = Some(expr.clone());
        match expr {
            Expr::Seq(lhs, rhs) => {
                self.right_branches.push(*rhs);
                self.next = Some(*lhs);
            }
            Expr::Choice(lhs, rhs) => {
                self.right_branches.push(*rhs);
                self.next = Some(*lhs);
            }
            Expr::PosPred(expr)
            | Expr::NegPred(expr)
            | Expr::Rep(expr)
            | Expr::RepOnce(expr)
            | Expr::RepExact(expr, _)
            | Expr::RepMin(expr, _)
            | Expr::RepMax(expr, _)
            | Expr::RepMinMax(expr, ..)
            | Expr::Opt(expr)
            | Expr::Push(expr) => {
                self.next = Some(*expr);
            }
            _ => {
                self.next = None;
            }
        }
    }
}

impl Iterator for ExprTopDownIterator {
    type Item = Expr;

    fn next(&mut self) -> Option<Self::Item> {
        let result = self.current.take();

        if let Some(expr) = self.next.take() {
            self.iterate_expr(expr);
        } else if let Some(expr) = self.right_branches.pop() {
            self.iterate_expr(expr);
        }

        result
    }
}

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

    #[test]
    fn top_down_iterator() {
        let expr = Expr::Choice(
            Box::new(Expr::Str(String::from("a"))),
            Box::new(Expr::Str(String::from("b")))
        );
        let mut top_down = expr.clone().iter_top_down();
        assert_eq!(top_down.next(), Some(expr));
        assert_eq!(top_down.next(), Some(Expr::Str(String::from("a"))));
        assert_eq!(top_down.next(), Some(Expr::Str(String::from("b"))));
        assert_eq!(top_down.next(), None);
    }

    #[test]
    fn identity() {
        let expr = Expr::Choice(
            Box::new(Expr::Seq(
                Box::new(Expr::Ident("a".to_owned())),
                Box::new(Expr::Str("b".to_owned()))
            )),
            Box::new(Expr::PosPred(Box::new(Expr::NegPred(Box::new(Expr::Rep(
                Box::new(Expr::RepOnce(Box::new(Expr::Opt(Box::new(Expr::Choice(
                    Box::new(Expr::Insens("c".to_owned())),
                    Box::new(Expr::Push(Box::new(Expr::Range(
                        "'d'".to_owned(),
                        "'e'".to_owned()
                    ))))
                ))))))
            ))))))
        );

        assert_eq!(
            expr.clone()
                .map_bottom_up(|expr| expr)
                .map_top_down(|expr| expr),
            expr
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::BinaryHeap;
use std::cmp::Ord;

pub(crate) fn k_smallest<T: Ord, I: Iterator<Item = T>>(mut iter: I, k: usize) -> BinaryHeap<T> {
    if k == 0 { return BinaryHeap::new(); }

    let mut heap = iter.by_ref().take(k).collect::<BinaryHeap<_>>();

    for i in iter {
        debug_assert_eq!(heap.len(), k);
        // Equivalent to heap.push(min(i, heap.pop())) but more efficient.
        // This should be done with a single `.peek_mut().unwrap()` but
        //  `PeekMut` sifts-down unconditionally on Rust 1.46.0 and prior.
        if *heap.peek().unwrap() > i {
            *heap.peek_mut().unwrap() = i;
        }
    }

    heap
}
<commit_msg>Make k_smallest work with just `alloc`<commit_after>use alloc::collections::BinaryHeap;
use core::cmp::Ord;

pub(crate) fn k_smallest<T: Ord, I: Iterator<Item = T>>(mut iter: I, k: usize) -> BinaryHeap<T> {
    if k == 0 { return BinaryHeap::new(); }

    let mut heap = iter.by_ref().take(k).collect::<BinaryHeap<_>>();

    for i in iter {
        debug_assert_eq!(heap.len(), k);
        // Equivalent to heap.push(min(i, heap.pop())) but more efficient.
        // This should be done with a single `.peek_mut().unwrap()` but
        //  `PeekMut` sifts-down unconditionally on Rust 1.46.0 and prior.
        if *heap.peek().unwrap() > i {
            *heap.peek_mut().unwrap() = i;
        }
    }

    heap
}
<|endoftext|>


<commit_before>use toml:: { Parser, Decoder, Value };
use rustc_serialize:: { Decodable };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::convert:: { From };

#[derive(RustcDecodable)]
pub struct Configuration {
    server: Server
}

#[derive(RustcDecodable)]
pub struct Server {
    host: String,
    port: i64
}

impl<'a> From<&'a Path> for Configuration {
    fn from(path: &'a Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Server {
    fn default() -> Self {
        Server {
            host: "127.0.0.1".to_string(),
            port: 6767
        }
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            server: Server::default()
        }
    }
}

pub fn from_toml_file(path: &Path) -> Result<Configuration> {
    let content = read_file(path).unwrap();
    let toml = &content[..];
    let value = Parser::new(toml).parse().unwrap();
    let mut decoder = Decoder::new(Value::Table(value));
    let configuration = Configuration::decode(&mut decoder).unwrap();
    Ok(configuration)
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}

#[cfg(test)]
mod tests {
    use std::path:: { Path };
    use std::env:: { current_dir };
    use configuration:: { read_file };

    #[test]
    fn test_read_file() {
        let cwd = current_dir().unwrap();
        let path = Path::new(&cwd).join("tests/fixtures/server.toml");
        let content = read_file(path.as_path());
        let expected = r#"[server]
host = "127.0.0.1"
port = 3000
"#;

        assert_eq!(content.unwrap(), expected.to_string());
    }
}
<commit_msg>add default  test<commit_after>use toml:: { Parser, Decoder, Value };
use rustc_serialize:: { Decodable };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::convert:: { From };

#[derive(RustcDecodable)]
pub struct Configuration {
    server: Server
}

#[derive(RustcDecodable)]
pub struct Server {
    host: String,
    port: i64
}

impl<'a> From<&'a Path> for Configuration {
    fn from(path: &'a Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Server {
    fn default() -> Self {
        Server {
            host: "127.0.0.1".to_string(),
            port: 6767
        }
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            server: Server::default()
        }
    }
}

pub fn from_toml_file(path: &Path) -> Result<Configuration> {
    let content = read_file(path).unwrap();
    let toml = &content[..];
    let value = Parser::new(toml).parse().unwrap();
    let mut decoder = Decoder::new(Value::Table(value));
    let configuration = Configuration::decode(&mut decoder).unwrap();
    Ok(configuration)
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}

#[cfg(test)]
mod tests {
    use std::path:: { Path };
    use std::env:: { current_dir };
    use configuration:: { read_file, Server, Configuration };

    #[test]
    fn test_read_file() {
        let cwd = current_dir().unwrap();
        let path = Path::new(&cwd).join("tests/fixtures/server.toml");
        let content = read_file(path.as_path());
        let expected = r#"[server]
host = "127.0.0.1"
port = 3000
"#;

        assert_eq!(content.unwrap(), expected.to_string());
    }

    #[test]
    fn test_server_default() {
        let server = Server::default();

        assert_eq!(server.host, "127.0.0.1".to_string());
        assert_eq!(server.port, 6767);
    }

    #[test]
    fn test_config_default() {
        let config = Configuration::default();

        assert_eq!(config.server.host, "127.0.0.1".to_string());
        assert_eq!(config.server.port, 6767);
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use conn::Conn;
use conn::stmt::futures::*;
use byteorder::ReadBytesExt;
use byteorder::LittleEndian as LE;
use errors::*;
use proto::Column;
use value::FromRow;
use value::Params;

pub mod futures;

/// Inner statement representation.
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct InnerStmt {
    /// Positions and names of named parameters
    pub named_params: Option<Vec<String>>,
    pub params: Option<Vec<Column>>,
    pub columns: Option<Vec<Column>>,
    pub statement_id: u32,
    pub num_columns: u16,
    pub num_params: u16,
    pub warning_count: u16,
}

impl InnerStmt {
    // TODO: Consume payload?
    pub fn new(pld: &[u8], named_params: Option<Vec<String>>) -> Result<InnerStmt> {
        let mut reader = &pld[1..];
        let statement_id = reader.read_u32::<LE>()?;
        let num_columns = reader.read_u16::<LE>()?;
        let num_params = reader.read_u16::<LE>()?;
        let warning_count = reader.read_u16::<LE>()?;
        Ok(InnerStmt {
            named_params: named_params,
            statement_id: statement_id,
            num_columns: num_columns,
            num_params: num_params,
            warning_count: warning_count,
            params: None,
            columns: None,
        })
    }
}

/// Prepered MySql statement.
#[derive(Debug)]
pub struct Stmt {
    stmt: InnerStmt,
    conn: Conn,
}

pub fn new_stmt(stmt: InnerStmt, conn: Conn) -> Stmt {
    Stmt {
        stmt: stmt,
        conn: conn,
    }
}

impl Stmt {
    /// Returns future that executes statement and resolves to `BinQueryResult`.
    pub fn execute<T: Into<Params>>(self, params: T) -> Execute {
        new_execute(self, params.into())
    }

    /// Returns future that performs batch execution of statement and resolves to `Stmt`.
    ///
    /// All results will be dropped.
    pub fn batch<T: Into<Params>>(self, params_vec: Vec<T>) -> Batch {
        new_batch(self, params_vec)
    }

    /// Returns future that executes statement and resolves to a first row of result if any.
    ///
    /// Returned future will call `R::from_row(row)` internally.
    pub fn first<T: Into<Params>, R: FromRow>(self, params: T) -> First<R> {
        new_first::<R>(self, params.into())
    }

    /// Unwraps `Conn`.
    pub fn unwrap(self) -> Conn {
        self.conn
    }

    #[doc(hidden)]
    pub fn num_params(&self) -> u16 {
        self.stmt.num_params
    }

    #[doc(hidden)]
    pub fn num_columns(&self) -> u16 {
        self.stmt.num_columns
    }

    #[doc(hidden)]
    pub fn id(&self) -> u32 {
        self.stmt.statement_id
    }

    #[doc(hidden)]
    pub fn params(&self) -> Option<&[Column]> {
        self.stmt.params.as_ref().map(|x| &**x)
    }

    #[doc(hidden)]
    pub fn named_params(&self) -> Option<&[String]> {
        self.stmt.named_params.as_ref().map(|x| &**x)
    }
}
<commit_msg>Fix typo<commit_after>// Copyright (c) 2016 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use conn::Conn;
use conn::stmt::futures::*;
use byteorder::ReadBytesExt;
use byteorder::LittleEndian as LE;
use errors::*;
use proto::Column;
use value::FromRow;
use value::Params;

pub mod futures;

/// Inner statement representation.
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct InnerStmt {
    /// Positions and names of named parameters
    pub named_params: Option<Vec<String>>,
    pub params: Option<Vec<Column>>,
    pub columns: Option<Vec<Column>>,
    pub statement_id: u32,
    pub num_columns: u16,
    pub num_params: u16,
    pub warning_count: u16,
}

impl InnerStmt {
    // TODO: Consume payload?
    pub fn new(pld: &[u8], named_params: Option<Vec<String>>) -> Result<InnerStmt> {
        let mut reader = &pld[1..];
        let statement_id = reader.read_u32::<LE>()?;
        let num_columns = reader.read_u16::<LE>()?;
        let num_params = reader.read_u16::<LE>()?;
        let warning_count = reader.read_u16::<LE>()?;
        Ok(InnerStmt {
            named_params: named_params,
            statement_id: statement_id,
            num_columns: num_columns,
            num_params: num_params,
            warning_count: warning_count,
            params: None,
            columns: None,
        })
    }
}

/// Prepared MySql statement.
#[derive(Debug)]
pub struct Stmt {
    stmt: InnerStmt,
    conn: Conn,
}

pub fn new_stmt(stmt: InnerStmt, conn: Conn) -> Stmt {
    Stmt {
        stmt: stmt,
        conn: conn,
    }
}

impl Stmt {
    /// Returns future that executes statement and resolves to `BinQueryResult`.
    pub fn execute<T: Into<Params>>(self, params: T) -> Execute {
        new_execute(self, params.into())
    }

    /// Returns future that performs batch execution of statement and resolves to `Stmt`.
    ///
    /// All results will be dropped.
    pub fn batch<T: Into<Params>>(self, params_vec: Vec<T>) -> Batch {
        new_batch(self, params_vec)
    }

    /// Returns future that executes statement and resolves to a first row of result if any.
    ///
    /// Returned future will call `R::from_row(row)` internally.
    pub fn first<T: Into<Params>, R: FromRow>(self, params: T) -> First<R> {
        new_first::<R>(self, params.into())
    }

    /// Unwraps `Conn`.
    pub fn unwrap(self) -> Conn {
        self.conn
    }

    #[doc(hidden)]
    pub fn num_params(&self) -> u16 {
        self.stmt.num_params
    }

    #[doc(hidden)]
    pub fn num_columns(&self) -> u16 {
        self.stmt.num_columns
    }

    #[doc(hidden)]
    pub fn id(&self) -> u32 {
        self.stmt.statement_id
    }

    #[doc(hidden)]
    pub fn params(&self) -> Option<&[Column]> {
        self.stmt.params.as_ref().map(|x| &**x)
    }

    #[doc(hidden)]
    pub fn named_params(&self) -> Option<&[String]> {
        self.stmt.named_params.as_ref().map(|x| &**x)
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2019 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use crate::token::Token;
use crate::error::{Result, Error, Source};
use crate::book::Book;

use std::mem;
use std::fs::File;
use std::path::Path;
use std::convert::AsRef;
use std::io::Read;
use std::ops::BitOr;

use comrak::{parse_document, Arena, ComrakOptions};
use comrak::nodes::{AstNode, NodeValue, ListType};

#[derive(Debug, Copy, Clone, PartialEq)]
/// The list of features used in a document.
pub struct Features {
    pub image: bool,
    pub footnote: bool,
    pub blockquote: bool,
    pub codeblock: bool,
    pub ordered_list: bool,
    pub table: bool,
    pub url: bool,
    pub subscript: bool,
    pub superscript: bool,
    pub strikethrough: bool,
}

impl Features {
    /// Creates a new set of features where all are set to false
    pub fn new() -> Features {
        Features {
            image: false,
            blockquote: false,
            codeblock: false,
            ordered_list: false,
            footnote: false,
            table: false,
            url: false,
            subscript: false,
            superscript: false,
            strikethrough: false,
        }
    }
}

impl BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Features {
            image: self.image | rhs.image,
            blockquote: self.blockquote | rhs.blockquote,
            codeblock: self.codeblock | rhs.codeblock,
            ordered_list: self.ordered_list | rhs.ordered_list,
            footnote: self.footnote | rhs.footnote,
            table: self.table | rhs.table,
            url: self.url | rhs.url,
            subscript: self.subscript | rhs.subscript,
            superscript: self.superscript | rhs.superscript,
            strikethrough: self.strikethrough | rhs.strikethrough
        }
    }
}

/// A parser that reads markdown and convert it to AST (a vector of `Token`s)
///
/// This AST can then be used by various renderes.
///
/// As this Parser uses Pulldown-cmark's one, it should be able to parse most
/// *valid* CommonMark variant of Markdown.
///
/// Compared to other Markdown parser, it might fail more often on invalid code, e.g.
/// footnotes references that are not defined anywhere.
///
/// # Examples
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some *valid* Markdown[^1]\n\n[^1]: with a valid footnote");
/// assert!(result.is_ok());
/// ```
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some footnote pointing to nothing[^1] ");
/// assert!(result.is_err());
/// ```
pub struct Parser {
    source: Source,
    features: Features,

    html_as_text: bool,
    superscript: bool,
}

impl Parser {
    /// Creates a parser
    pub fn new() -> Parser {
        Parser {
            source: Source::empty(),
            features: Features::new(),
            html_as_text: true,
            superscript: false,
        }
    }

    /// Creates a parser with options from a book configuration file
    pub fn from(book: &Book) -> Parser {
        let mut parser = Parser::new();
        parser.html_as_text = book.options.get_bool("crowbook.html_as_text").unwrap();
        parser.superscript = book.options.get_bool("crowbook.markdown.superscript").unwrap();
        parser
    }

    /// Enable/disable HTML as text
    pub fn html_as_text(&mut self, b: bool) {
        self.html_as_text = b;
    }

    /// Sets a parser's source file
    pub fn set_source_file(&mut self, s: &str) {
        self.source = Source::new(s);
    }

    /// Parse a file and returns an AST or  an error
    pub fn parse_file<P: AsRef<Path>>(&mut self, filename: P) -> Result<Vec<Token>> {
        let path: &Path = filename.as_ref();
        let mut f = File::open(path)
            .map_err(|_| {
                Error::file_not_found(&self.source,
                                      lformat!("markdown file"),
                                      format!("{}", path.display()))
            })?;
        let mut s = String::new();

        f.read_to_string(&mut s)
            .map_err(|_| {
                Error::parser(&self.source,
                              lformat!("file {file} contains invalid UTF-8, could not parse it",
                                       file = path.display()))
            })?;
        self.parse(&s)
    }

    /// Parse a string and returns an AST  an Error.
    pub fn parse(&mut self, s: &str) -> Result<Vec<Token>> {
        let arena = Arena::new();

        // Set options for comrak
        let mut options = ComrakOptions::default();
        options.hardbreaks = false;
        options.smart = false;
        options.ext_strikethrough = true;
        options.ext_table = true;
        options.ext_autolink = true;
        options.ext_tasklist = true;
        options.ext_superscript = false;
        options.ext_footnotes = true;
        options.ext_description_lists = true;

        let root = parse_document(&arena, s, &options);

        let mut res = self.parse_node(root)?;

        collapse(&mut res);

        find_standalone(&mut res);

        Ok(res)
    }

    /// Parse an inline string and returns a list of `Token`.
    ///
    /// This function removes the outermost `Paragraph` in most of the
    /// cases, as it is meant to be used for an inline string (e.g. metadata)
    pub fn parse_inline(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut tokens = self.parse(s)?;
        // Unfortunately, parser will put all this in a paragraph, so we might need to remove it.
        if tokens.len() == 1 {
            let res = match tokens[0] {
                Token::Paragraph(ref mut v) => Some(mem::replace(v, vec![])),
                _ => None,
            };
            match res {
                Some(tokens) => Ok(tokens),
                _ => Ok(tokens),
            }
        } else {
            Ok(tokens)
        }
    }

    /// Returns the list of features used by this parser
    pub fn features(&self) -> Features {
        self.features
    }

    fn parse_node<'a>(&mut self,
                      node: &'a AstNode<'a>)
                      -> Result<Vec<Token>> {
        let mut inner = vec![];
        for c in node.children() {
            let mut v = self.parse_node(c)?;
            inner.append(&mut v);
        }

        inner = match node.data.borrow().value {
            NodeValue::Document => inner,
            NodeValue::BlockQuote => {
                self.features.blockquote = true;
                vec![Token::BlockQuote(inner)]
            },
            NodeValue::List(ref list) => {
                // Todo: use "tight" feature?
                match list.list_type {
                    ListType::Bullet => vec![Token::List(inner)],
                    ListType::Ordered => vec![Token::OrderedList(list.start, inner)]
                }
            },
            NodeValue::Item(_) => vec![Token::Item(inner)],
            NodeValue::DescriptionList => vec![Token::DescriptionList(inner)],
            NodeValue::DescriptionItem(_) => vec![Token::DescriptionItem(inner)],
            NodeValue::DescriptionTerm => vec![Token::DescriptionTerm(inner)],
            NodeValue::DescriptionDetails => vec![Token::DescriptionDetails(inner)],
            NodeValue::CodeBlock(ref block) => {
                let info = String::from_utf8(block.info.clone()).map_err(|_| Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8")))?;
                let code = String::from_utf8(block.literal.clone()).map_err(|_| Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8")))?;
                self.features.codeblock = true;
                vec!(Token::CodeBlock(info, code))
            },
            NodeValue::HtmlBlock(ref block) => {
                let text = String::from_utf8(block.literal.clone()).map_err(|_| Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8")))?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            },
            NodeValue::HtmlInline(ref html) => {
                let text = String::from_utf8(html.clone()).map_err(|_| Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8")))?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            },
            NodeValue::Paragraph => {
                vec![Token::Paragraph(inner)]
            }
            NodeValue::Heading(ref heading) => {
                vec![Token::Header(heading.level as i32, inner)]
            },
            NodeValue::ThematicBreak => vec![Token::Rule],
            NodeValue::FootnoteDefinition(ref def) => {
                let reference = String::from_utf8(def.clone()).map_err(|_| Error::parser(&self.source, lformat!("Footnote definition contains invalid UTF-8")))?;
                vec![Token::FootnoteDefinition(reference, inner)]
            },
            NodeValue::Text(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| Error::parser(&self.source, lformat!("Markdown file contains invalid UTF-8")))?;
                vec![Token::Str(text)]
            },
            NodeValue::Code(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| Error::parser(&self.source, lformat!("Markdown file contains invalid UTF-8")))?;
                vec![Token::Code(text)]
            },
            NodeValue::SoftBreak => vec![Token::SoftBreak],
            NodeValue::LineBreak => vec![Token::HardBreak],
            NodeValue::Emph => vec![Token::Emphasis(inner)],
            NodeValue::Strong => vec![Token::Strong(inner)],
            NodeValue::Strikethrough => {
                self.features.strikethrough = true;
                vec![Token::Strikethrough(inner)]
            },
            NodeValue::Superscript => vec![Token::Superscript(inner)],
            NodeValue::Link(ref link) => {
                self.features.url = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| Error::parser(&self.source, lformat!("Link URL contains invalid UTF-8")))?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| Error::parser(&self.source, lformat!("Link title contains invalid UTF-8")))?;
                vec![Token::Link(url, title, inner)]
            },
            NodeValue::Image(ref link) => {
                self.features.image = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| Error::parser(&self.source, lformat!("Image URL contains invalid UTF-8")))?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| Error::parser(&self.source, lformat!("Image title contains invalid UTF-8")))?;
                vec![Token::Image(url, title, inner)]
            }
            NodeValue::FootnoteReference(ref name) => {
                let name = String::from_utf8(name.clone()).map_err(|_| Error::parser(&self.source, lformat!("Footnote reference contains invalid UTF-8")))?;

                vec![Token::FootnoteReference(name)]
            },
            NodeValue::TableCell => vec![Token::TableCell(inner)],
            NodeValue::TableRow(header) => {
                if header {
                    vec![Token::TableHead(inner)]
                } else {
                    vec![Token::TableRow(inner)]
                }
            },
            NodeValue::Table(ref aligns) => {
                self.features.table = true;
                // TODO: actually use alignements)
                vec![Token::Table(aligns.len() as i32, inner)]
            },
        };
        Ok(inner)
    }
}

/// Replace consecutives Strs by a Str of both, collapse soft breaks to previous std and so on
fn collapse(ast: &mut Vec<Token>) {
    let mut i = 0;
    while i < ast.len() {
        if ast[i].is_str() && i + 1 < ast.len() {
            if ast[i + 1].is_str() {
                // Two consecutives Str, concatenate them
                let token = ast.remove(i + 1);
                if let (&mut Token::Str(ref mut dest), Token::Str(ref source)) = (&mut ast[i],
                                                                                token) {
                    //                        dest.push(' ');
                    dest.push_str(source);
                    continue;
                } else {
                    unreachable!();
                }
            } else if ast[i + 1] == Token::SoftBreak {
                ast.remove(i + 1);
                if let &mut Token::Str(ref mut dest) = &mut ast[i] {
                    dest.push(' ');
                    continue;
                } else {
                    unreachable!();
                }
            }
        }

        // If token is containing others, recurse into them
        if let Some(ref mut inner) = ast[i].inner_mut() {
            collapse(inner);
        }
        i += 1;
    }
}

/// Replace images which are alone in a paragraph by standalone images
fn find_standalone(ast: &mut Vec<Token>) {
    for token in ast {
        let res = if let &mut Token::Paragraph(ref mut inner) = token {
            if inner.len() == 1 {
                if inner[0].is_image() {
                    if let Token::Image(source, title, inner) = mem::replace(&mut inner[0],
                                                                             Token::Rule) {
                        Token::StandaloneImage(source, title, inner)
                    } else {
                        unreachable!();
                    }
                } else {
                    // If paragraph only contains a link only containing an image, ok too
                    // Fixme: messy code and unnecessary clone
                    if let Token::Link(ref url, ref alt, ref mut inner) = inner[0] {
                        if inner[0].is_image() {
                            if let Token::Image(source, title, inner) = mem::replace(&mut inner[0],
                                                                                Token::Rule) {
                                Token::Link(url.clone(), alt.clone(), vec![Token::StandaloneImage(source, title, inner)])
                            } else {
                                unreachable!();
                            }
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                }
            } else {
                continue;
            }
        } else {
            continue;
        };

        *token = res;
    }
}

<commit_msg>Only set superscript to comrak if it is set to crowbook<commit_after>// Copyright (C) 2016-2019 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use crate::token::Token;
use crate::error::{Result, Error, Source};
use crate::book::Book;

use std::mem;
use std::fs::File;
use std::path::Path;
use std::convert::AsRef;
use std::io::Read;
use std::ops::BitOr;

use comrak::{parse_document, Arena, ComrakOptions};
use comrak::nodes::{AstNode, NodeValue, ListType};

#[derive(Debug, Copy, Clone, PartialEq)]
/// The list of features used in a document.
///
/// This is used by the renderers to only require some packages if they
/// are needed.
pub struct Features {
    pub image: bool,
    pub footnote: bool,
    pub blockquote: bool,
    pub codeblock: bool,
    pub ordered_list: bool,
    pub table: bool,
    pub url: bool,
    pub subscript: bool,
    pub superscript: bool,
    pub strikethrough: bool,
}

impl Features {
    /// Creates a new set of features where all are set to false
    pub fn new() -> Features {
        Features {
            image: false,
            blockquote: false,
            codeblock: false,
            ordered_list: false,
            footnote: false,
            table: false,
            url: false,
            subscript: false,
            superscript: false,
            strikethrough: false,
        }
    }
}

impl BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Features {
            image: self.image | rhs.image,
            blockquote: self.blockquote | rhs.blockquote,
            codeblock: self.codeblock | rhs.codeblock,
            ordered_list: self.ordered_list | rhs.ordered_list,
            footnote: self.footnote | rhs.footnote,
            table: self.table | rhs.table,
            url: self.url | rhs.url,
            subscript: self.subscript | rhs.subscript,
            superscript: self.superscript | rhs.superscript,
            strikethrough: self.strikethrough | rhs.strikethrough
        }
    }
}

/// A parser that reads markdown and convert it to AST (a vector of `Token`s)
///
/// This AST can then be used by various renderes.
///
/// As this Parser uses Pulldown-cmark's one, it should be able to parse most
/// *valid* CommonMark variant of Markdown.
///
/// Compared to other Markdown parser, it might fail more often on invalid code, e.g.
/// footnotes references that are not defined anywhere.
///
/// # Examples
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some *valid* Markdown[^1]\n\n[^1]: with a valid footnote");
/// assert!(result.is_ok());
/// ```
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some footnote pointing to nothing[^1] ");
/// assert!(result.is_err());
/// ```
pub struct Parser {
    source: Source,
    features: Features,

    html_as_text: bool,
    superscript: bool,
}

impl Parser {
    /// Creates a parser
    pub fn new() -> Parser {
        Parser {
            source: Source::empty(),
            features: Features::new(),
            html_as_text: true,
            superscript: false,
        }
    }

    /// Creates a parser with options from a book configuration file
    pub fn from(book: &Book) -> Parser {
        let mut parser = Parser::new();
        parser.html_as_text = book.options.get_bool("crowbook.html_as_text").unwrap();
        parser.superscript = book.options.get_bool("crowbook.markdown.superscript").unwrap();
        parser
    }

    /// Enable/disable HTML as text
    pub fn html_as_text(&mut self, b: bool) {
        self.html_as_text = b;
    }

    /// Sets a parser's source file
    pub fn set_source_file(&mut self, s: &str) {
        self.source = Source::new(s);
    }

    /// Parse a file and returns an AST or  an error
    pub fn parse_file<P: AsRef<Path>>(&mut self, filename: P) -> Result<Vec<Token>> {
        let path: &Path = filename.as_ref();
        let mut f = File::open(path)
            .map_err(|_| {
                Error::file_not_found(&self.source,
                                      lformat!("markdown file"),
                                      format!("{}", path.display()))
            })?;
        let mut s = String::new();

        f.read_to_string(&mut s)
            .map_err(|_| {
                Error::parser(&self.source,
                              lformat!("file {file} contains invalid UTF-8, could not parse it",
                                       file = path.display()))
            })?;
        self.parse(&s)
    }

    /// Parse a string and returns an AST  an Error.
    pub fn parse(&mut self, s: &str) -> Result<Vec<Token>> {
        let arena = Arena::new();

        // Set options for comrak
        let mut options = ComrakOptions::default();
        options.hardbreaks = false;
        options.smart = false;
        options.ext_strikethrough = true;
        options.ext_table = true;
        options.ext_autolink = true;
        options.ext_tasklist = true;
        options.ext_superscript = self.superscript;
        options.ext_footnotes = true;
        options.ext_description_lists = true;

        let root = parse_document(&arena, s, &options);

        let mut res = self.parse_node(root)?;

        collapse(&mut res);

        find_standalone(&mut res);

        Ok(res)
    }

    /// Parse an inline string and returns a list of `Token`.
    ///
    /// This function removes the outermost `Paragraph` in most of the
    /// cases, as it is meant to be used for an inline string (e.g. metadata)
    pub fn parse_inline(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut tokens = self.parse(s)?;
        // Unfortunately, parser will put all this in a paragraph, so we might need to remove it.
        if tokens.len() == 1 {
            let res = match tokens[0] {
                Token::Paragraph(ref mut v) => Some(mem::replace(v, vec![])),
                _ => None,
            };
            match res {
                Some(tokens) => Ok(tokens),
                _ => Ok(tokens),
            }
        } else {
            Ok(tokens)
        }
    }

    /// Returns the list of features used by this parser
    pub fn features(&self) -> Features {
        self.features
    }

    fn parse_node<'a>(&mut self,
                      node: &'a AstNode<'a>)
                      -> Result<Vec<Token>> {
        let mut inner = vec![];
        for c in node.children() {
            let mut v = self.parse_node(c)?;
            inner.append(&mut v);
        }

        inner = match node.data.borrow().value {
            NodeValue::Document => inner,
            NodeValue::BlockQuote => {
                self.features.blockquote = true;
                vec![Token::BlockQuote(inner)]
            },
            NodeValue::List(ref list) => {
                // Todo: use "tight" feature?
                match list.list_type {
                    ListType::Bullet => vec![Token::List(inner)],
                    ListType::Ordered => vec![Token::OrderedList(list.start, inner)]
                }
            },
            NodeValue::Item(_) => vec![Token::Item(inner)],
            NodeValue::DescriptionList => vec![Token::DescriptionList(inner)],
            NodeValue::DescriptionItem(_) => vec![Token::DescriptionItem(inner)],
            NodeValue::DescriptionTerm => vec![Token::DescriptionTerm(inner)],
            NodeValue::DescriptionDetails => vec![Token::DescriptionDetails(inner)],
            NodeValue::CodeBlock(ref block) => {
                let info = String::from_utf8(block.info.clone()).map_err(|_| Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8")))?;
                let code = String::from_utf8(block.literal.clone()).map_err(|_| Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8")))?;
                self.features.codeblock = true;
                vec!(Token::CodeBlock(info, code))
            },
            NodeValue::HtmlBlock(ref block) => {
                let text = String::from_utf8(block.literal.clone()).map_err(|_| Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8")))?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            },
            NodeValue::HtmlInline(ref html) => {
                let text = String::from_utf8(html.clone()).map_err(|_| Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8")))?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            },
            NodeValue::Paragraph => {
                vec![Token::Paragraph(inner)]
            }
            NodeValue::Heading(ref heading) => {
                vec![Token::Header(heading.level as i32, inner)]
            },
            NodeValue::ThematicBreak => vec![Token::Rule],
            NodeValue::FootnoteDefinition(ref def) => {
                let reference = String::from_utf8(def.clone()).map_err(|_| Error::parser(&self.source, lformat!("Footnote definition contains invalid UTF-8")))?;
                vec![Token::FootnoteDefinition(reference, inner)]
            },
            NodeValue::Text(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| Error::parser(&self.source, lformat!("Markdown file contains invalid UTF-8")))?;
                vec![Token::Str(text)]
            },
            NodeValue::Code(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| Error::parser(&self.source, lformat!("Markdown file contains invalid UTF-8")))?;
                vec![Token::Code(text)]
            },
            NodeValue::SoftBreak => vec![Token::SoftBreak],
            NodeValue::LineBreak => vec![Token::HardBreak],
            NodeValue::Emph => vec![Token::Emphasis(inner)],
            NodeValue::Strong => vec![Token::Strong(inner)],
            NodeValue::Strikethrough => {
                self.features.strikethrough = true;
                vec![Token::Strikethrough(inner)]
            },
            NodeValue::Superscript => vec![Token::Superscript(inner)],
            NodeValue::Link(ref link) => {
                self.features.url = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| Error::parser(&self.source, lformat!("Link URL contains invalid UTF-8")))?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| Error::parser(&self.source, lformat!("Link title contains invalid UTF-8")))?;
                vec![Token::Link(url, title, inner)]
            },
            NodeValue::Image(ref link) => {
                self.features.image = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| Error::parser(&self.source, lformat!("Image URL contains invalid UTF-8")))?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| Error::parser(&self.source, lformat!("Image title contains invalid UTF-8")))?;
                vec![Token::Image(url, title, inner)]
            }
            NodeValue::FootnoteReference(ref name) => {
                let name = String::from_utf8(name.clone()).map_err(|_| Error::parser(&self.source, lformat!("Footnote reference contains invalid UTF-8")))?;

                vec![Token::FootnoteReference(name)]
            },
            NodeValue::TableCell => vec![Token::TableCell(inner)],
            NodeValue::TableRow(header) => {
                if header {
                    vec![Token::TableHead(inner)]
                } else {
                    vec![Token::TableRow(inner)]
                }
            },
            NodeValue::Table(ref aligns) => {
                self.features.table = true;
                // TODO: actually use alignements)
                vec![Token::Table(aligns.len() as i32, inner)]
            },
        };
        Ok(inner)
    }
}

/// Replace consecutives Strs by a Str of both, collapse soft breaks to previous std and so on
fn collapse(ast: &mut Vec<Token>) {
    let mut i = 0;
    while i < ast.len() {
        if ast[i].is_str() && i + 1 < ast.len() {
            if ast[i + 1].is_str() {
                // Two consecutives Str, concatenate them
                let token = ast.remove(i + 1);
                if let (&mut Token::Str(ref mut dest), Token::Str(ref source)) = (&mut ast[i],
                                                                                token) {
                    //                        dest.push(' ');
                    dest.push_str(source);
                    continue;
                } else {
                    unreachable!();
                }
            } else if ast[i + 1] == Token::SoftBreak {
                ast.remove(i + 1);
                if let &mut Token::Str(ref mut dest) = &mut ast[i] {
                    dest.push(' ');
                    continue;
                } else {
                    unreachable!();
                }
            }
        }

        // If token is containing others, recurse into them
        if let Some(ref mut inner) = ast[i].inner_mut() {
            collapse(inner);
        }
        i += 1;
    }
}

/// Replace images which are alone in a paragraph by standalone images
fn find_standalone(ast: &mut Vec<Token>) {
    for token in ast {
        let res = if let &mut Token::Paragraph(ref mut inner) = token {
            if inner.len() == 1 {
                if inner[0].is_image() {
                    if let Token::Image(source, title, inner) = mem::replace(&mut inner[0],
                                                                             Token::Rule) {
                        Token::StandaloneImage(source, title, inner)
                    } else {
                        unreachable!();
                    }
                } else {
                    // If paragraph only contains a link only containing an image, ok too
                    // Fixme: messy code and unnecessary clone
                    if let Token::Link(ref url, ref alt, ref mut inner) = inner[0] {
                        if inner[0].is_image() {
                            if let Token::Image(source, title, inner) = mem::replace(&mut inner[0],
                                                                                Token::Rule) {
                                Token::Link(url.clone(), alt.clone(), vec![Token::StandaloneImage(source, title, inner)])
                            } else {
                                unreachable!();
                            }
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                }
            } else {
                continue;
            }
        } else {
            continue;
        };

        *token = res;
    }
}

<|endoftext|>


<commit_before>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use self::chrono::format::ParseError;
use std::error::Error;
use std::fmt::{Display, Formatter, Result as fmtResult};

pub struct ELBLogEntry {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: String,
    backend_address: String,
    request_processing_time: f32,
    backend_processing_time: String,
    response_processing_time: String,
    elb_status_code: String,
    backend_status_code: String,
    received_bytes: String,
    sent_bytes: String,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|x| {
                        parse_line(&(x.unwrap()))
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

#[derive(Debug)]
pub struct ParsingError{
    property: &'static str,
    inner_description: String,
}

impl Display for ParsingError {
    fn fmt(&self, f: &mut Formatter) -> fmtResult {
        write!(
            f,
            "Failed to parse {}. The failure messae is {}",
            self.property,
            self.inner_description
        )
    }
}

impl Error for ParsingError {
    fn description(&self) -> &str {
        &self.inner_description
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

const TIMESTAMP: &'static str = "timestamp";

pub fn parse_line(line: &String) -> Result<Box<ELBLogEntry>, Vec<ParsingError>> {
    let split_line: Vec<_> = line.split(" ").collect();
    let mut errors = Vec::new();

    let ts = match split_line[0].parse() {
        Ok(parsed_ts) => Some(parsed_ts),

        Err(e) => {
            errors.push(
                ParsingError {
                    property: TIMESTAMP,
                    //TODO Figure out a way to pass ownership of the original error to the ParsingError to make it available to callers.
                    inner_description: (e as ParseError).description().to_string(),
                }
            );
            None
        }
    };

    if errors.is_empty() {
        Ok(
            Box::new(
                ELBLogEntry {
                    timestamp: ts.unwrap(),
                    elb_name: split_line[1].to_string(),
                    client_address: split_line[2].to_string(),
                    backend_address: split_line[3].to_string(),
                    request_processing_time: split_line[4].parse::<f32>().unwrap(),  //TODO This needs to be error checked once I figure out how to handle errors.
                    backend_processing_time: split_line[5].to_string(),
                    response_processing_time: split_line[6].to_string(),
                    elb_status_code: split_line[7].to_string(),
                    backend_status_code: split_line[8].to_string(),
                    received_bytes: split_line[9].to_string(),
                    sent_bytes: split_line[10].to_string(),
                    request_method: split_line[11].trim_matches('"').to_string(),
                    request_url: split_line[12].to_string(),
                    request_http_version: split_line[13].trim_matches('"').to_string()
                }
            )
        )
    } else {
        Err(errors)
    }
}

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

    const TEST_LINE: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
    ";

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_http_version() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_url() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_method() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_method, "GET")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_sent_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.sent_bytes, "7582")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_received_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.received_bytes, "0")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_response_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.response_processing_time, "0.00003")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_processing_time, "0.145507")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_address, "172.16.1.5:9000")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_client_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.client_address, "172.16.1.6:54814")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_timestamp() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_log_entry.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_name() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_name, "elb-name")
	}
}
<commit_msg>Updated some notes.<commit_after>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use self::chrono::format::ParseError;
use std::error::Error;
use std::fmt::{Display, Formatter, Result as fmtResult};

pub struct ELBLogEntry {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: String,
    backend_address: String,
    request_processing_time: f32,
    backend_processing_time: String,
    response_processing_time: String,
    elb_status_code: String,
    backend_status_code: String,
    received_bytes: String,
    sent_bytes: String,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|x| {
                        parse_line(&(x.unwrap()))
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

#[derive(Debug)]
pub struct ParsingError{
    property: &'static str,
    inner_description: String,
}

impl Display for ParsingError {
    fn fmt(&self, f: &mut Formatter) -> fmtResult {
        write!(
            f,
            "Failed to parse {}. The failure messae is {}",
            self.property,
            self.inner_description
        )
    }
}

impl Error for ParsingError {
    fn description(&self) -> &str {
        &self.inner_description
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

struct ParsingErrors {
    record: String,
    errors: Vec<ParsingError>,
}

const TIMESTAMP: &'static str = "timestamp";

pub fn parse_line(line: &String) -> Result<Box<ELBLogEntry>, Vec<ParsingError>> {
    let split_line: Vec<_> = line.split(" ").collect();
    let mut errors = Vec::new();

    let ts = match split_line[0].parse() {
        Ok(parsed_ts) => Some(parsed_ts),

        Err(e) => {
            errors.push(
                ParsingError {
                    property: TIMESTAMP,
                    //TODO Figure out a way to pass ownership of the original error to the ParsingError to make it available to callers.
                    inner_description: (e as ParseError).description().to_string(),
                }
            );
            None
        }
    };

    if errors.is_empty() {
        Ok(
            Box::new(
                ELBLogEntry {
                    timestamp: ts.unwrap(),
                    elb_name: split_line[1].to_string(),
                    client_address: split_line[2].to_string(),
                    backend_address: split_line[3].to_string(),
                    request_processing_time: split_line[4].parse::<f32>().unwrap(),  //TODO This needs to be error checked once I figure out how to handle errors.
                    backend_processing_time: split_line[5].to_string(),
                    response_processing_time: split_line[6].to_string(),
                    elb_status_code: split_line[7].to_string(),
                    backend_status_code: split_line[8].to_string(),
                    received_bytes: split_line[9].to_string(),
                    sent_bytes: split_line[10].to_string(),
                    request_method: split_line[11].trim_matches('"').to_string(),
                    request_url: split_line[12].to_string(),
                    request_http_version: split_line[13].trim_matches('"').to_string()
                }
            )
        )
    } else {
        Err(errors)
    }
}

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

    const TEST_LINE: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
    ";

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_http_version() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_url() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_method() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_method, "GET")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_sent_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.sent_bytes, "7582")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_received_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.received_bytes, "0")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_status_code, "200")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_response_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.response_processing_time, "0.00003")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_processing_time, "0.145507")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_address, "172.16.1.5:9000")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_client_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.client_address, "172.16.1.6:54814")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_timestamp() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_log_entry.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_name() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_name, "elb-name")
	}
}
<|endoftext|>


<commit_before>use bindings::*;
use context::Context;
use function::Function;
use libc::c_uint;
use util::NativeRef;
use std::fmt::Show;
use std::kinds::marker::ContravariantLifetime;
use std::mem::transmute;
use std::iter::Iterator;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
/// An ELF dependency iterator
pub struct Needed<'a> {
    _reader: jit_readelf_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Needed<'a> {
    #[inline(always)]
    fn new(read:&ReadElf<'a>) -> Needed<'a> {
        unsafe {
            Needed {
                _reader: read.as_ptr(),
                index: 0 as c_uint,
                length: jit_readelf_num_needed(read.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<String> for Needed<'a> {
    fn next(&mut self) -> Option<String> {
        let index = self.index;
        self.index += 1;
        unsafe {
            if index < self.length {
                let c_name = jit_readelf_get_needed(self._reader, index);
                let name = from_c_str(c_name);
                Some(name)
            } else {
                None
            }
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<String> {
        self.index += n as c_uint;
        self.next()
    }
}
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t, ContravariantLifetime)
impl<'a> ReadElf<'a> {
    /// Open a new ELF binary
    pub fn new<S:ToCStr+Show>(filename:S) -> ReadElf<'a> {
        unsafe {
            let mut this = RawPtr::null();
            let code = filename.with_c_str(|c_name|
                jit_readelf_open(&mut this, c_name, 0)
            );
            if this.is_null() {
                fail!("'{}' couldn't be opened due to {}", filename, code);
            } else {
                NativeRef::from_ptr(this)
            }
        }
    }
    #[inline]
    /// Get the name of this ELF binary
    pub fn get_name(&self) -> String {
        unsafe {
            from_c_str(jit_readelf_get_name(self.as_ptr()))
        }
    }
    #[inline]
    pub fn add_to_context(&self, ctx:&Context<'a>) {
        unsafe {
            jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
        }
    }
    #[inline]
    /// Get a symbol in the ELF binary
    pub unsafe fn get_symbol<T, S:ToCStr>(&self, symbol:S) -> &'a mut T {
        symbol.with_c_str(|c_symbol|
            transmute(jit_readelf_get_symbol(self.as_ptr(), c_symbol))
        )
    }
    #[inline]
    /// Iterate over the needed libraries
    pub fn iter_needed<'a>(&'a self) -> Needed<'a> {
        Needed::new(self)
    }
}
#[unsafe_destructor]
impl<'a> Drop for ReadElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_readelf_close(self.as_ptr())
        }
    }
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t, ContravariantLifetime)
impl<'a> WriteElf<'a> {
    #[inline]
    /// Create a new ELF binary reader
    pub fn new<S:ToCStr>(lib_name:S) -> WriteElf<'a> {
        lib_name.with_c_str(|c_lib_name| unsafe {
            NativeRef::from_ptr(jit_writeelf_create(c_lib_name))
        })
    }
    #[inline]
    /// Write to the filename given (not implemented by LibJIT yet)
    pub fn write<S:ToCStr>(&self, filename:S) -> bool {
        filename.with_c_str(|c_filename| unsafe {
            jit_writeelf_write(self.as_ptr(), c_filename) != 0
        })
    }
    #[inline]
    /// Add a function to the ELF
    pub fn add_function<S:ToCStr>(&self, func:&Function<'a>, name:S) -> bool {
        name.with_c_str(|c_name| unsafe {
            jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), c_name) != 0
        })
    }
    #[inline]
    /// Add a dependency to the ELF
    pub fn add_needed<S:ToCStr>(&self, lib_name:S) -> bool {
        lib_name.with_c_str(|c_lib_name| unsafe {
            jit_writeelf_add_needed(self.as_ptr(), c_lib_name) != 0
        })
    }
}
#[unsafe_destructor]
impl<'a> Drop for WriteElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_writeelf_destroy(self.as_ptr())
        }
    }
}<commit_msg>Rename `iter_needed` in `ReadElf` to `needed`<commit_after>use bindings::*;
use context::Context;
use function::Function;
use libc::c_uint;
use util::NativeRef;
use std::fmt::Show;
use std::kinds::marker::ContravariantLifetime;
use std::mem::transmute;
use std::iter::Iterator;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
/// An ELF dependency iterator
pub struct Needed<'a> {
    _reader: jit_readelf_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Needed<'a> {
    #[inline(always)]
    fn new(read:&ReadElf<'a>) -> Needed<'a> {
        unsafe {
            Needed {
                _reader: read.as_ptr(),
                index: 0 as c_uint,
                length: jit_readelf_num_needed(read.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<String> for Needed<'a> {
    fn next(&mut self) -> Option<String> {
        let index = self.index;
        self.index += 1;
        unsafe {
            if index < self.length {
                let c_name = jit_readelf_get_needed(self._reader, index);
                let name = from_c_str(c_name);
                Some(name)
            } else {
                None
            }
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<String> {
        self.index += n as c_uint;
        self.next()
    }
}
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t, ContravariantLifetime)
impl<'a> ReadElf<'a> {
    /// Open a new ELF binary
    pub fn new<S:ToCStr+Show>(filename:S) -> ReadElf<'a> {
        unsafe {
            let mut this = RawPtr::null();
            let code = filename.with_c_str(|c_name|
                jit_readelf_open(&mut this, c_name, 0)
            );
            if this.is_null() {
                fail!("'{}' couldn't be opened due to {}", filename, code);
            } else {
                NativeRef::from_ptr(this)
            }
        }
    }
    #[inline]
    /// Get the name of this ELF binary
    pub fn get_name(&self) -> String {
        unsafe {
            from_c_str(jit_readelf_get_name(self.as_ptr()))
        }
    }
    #[inline]
    pub fn add_to_context(&self, ctx:&Context<'a>) {
        unsafe {
            jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
        }
    }
    #[inline]
    /// Get a symbol in the ELF binary
    pub unsafe fn get_symbol<T, S:ToCStr>(&self, symbol:S) -> &'a mut T {
        symbol.with_c_str(|c_symbol|
            transmute(jit_readelf_get_symbol(self.as_ptr(), c_symbol))
        )
    }
    #[inline]
    /// Iterate over the needed libraries
    pub fn needed<'a>(&'a self) -> Needed<'a> {
        Needed::new(self)
    }
}
#[unsafe_destructor]
impl<'a> Drop for ReadElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_readelf_close(self.as_ptr())
        }
    }
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t, ContravariantLifetime)
impl<'a> WriteElf<'a> {
    #[inline]
    /// Create a new ELF binary reader
    pub fn new<S:ToCStr>(lib_name:S) -> WriteElf<'a> {
        lib_name.with_c_str(|c_lib_name| unsafe {
            NativeRef::from_ptr(jit_writeelf_create(c_lib_name))
        })
    }
    #[inline]
    /// Write to the filename given (not implemented by LibJIT yet)
    pub fn write<S:ToCStr>(&self, filename:S) -> bool {
        filename.with_c_str(|c_filename| unsafe {
            jit_writeelf_write(self.as_ptr(), c_filename) != 0
        })
    }
    #[inline]
    /// Add a function to the ELF
    pub fn add_function<S:ToCStr>(&self, func:&Function<'a>, name:S) -> bool {
        name.with_c_str(|c_name| unsafe {
            jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), c_name) != 0
        })
    }
    #[inline]
    /// Add a dependency to the ELF
    pub fn add_needed<S:ToCStr>(&self, lib_name:S) -> bool {
        lib_name.with_c_str(|c_lib_name| unsafe {
            jit_writeelf_add_needed(self.as_ptr(), c_lib_name) != 0
        })
    }
}
#[unsafe_destructor]
impl<'a> Drop for WriteElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_writeelf_destroy(self.as_ptr())
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

#[forbid(deprecated_mode)];
//! Additional general-purpose comparison functionality.

use core::f32;
use core::f64;
use core::float;

const fuzzy_epsilon: float = 1.0e-6;

pub trait FuzzyEq {
    pure fn fuzzy_eq(&self, other: &Self) -> bool;
    pure fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Self) -> bool;
}

impl float: FuzzyEq {
    pure fn fuzzy_eq(&self, other: &float) -> bool {
        self.fuzzy_eq_eps(other, &fuzzy_epsilon)
    }

    pure fn fuzzy_eq_eps(&self, other: &float, epsilon: &float) -> bool {
        float::abs(*self - *other) < *epsilon
    }
}

impl f32: FuzzyEq {
    pure fn fuzzy_eq(&self, other: &f32) -> bool {
        self.fuzzy_eq_eps(other, &(fuzzy_epsilon as f32))
    }

    pure fn fuzzy_eq_eps(&self, other: &f32, epsilon: &f32) -> bool {
        f32::abs(*self - *other) < *epsilon
    }
}

impl f64: FuzzyEq {
    pure fn fuzzy_eq(&self, other: &f64) -> bool {
        self.fuzzy_eq_eps(other, &(fuzzy_epsilon as f64))
    }

    pure fn fuzzy_eq_eps(&self, other: &f64, epsilon: &f64) -> bool {
        f64::abs(*self - *other) < *epsilon
    }
}

#[test]
fn test_fuzzy_equals() {
    assert (&1.0f).fuzzy_eq(&1.0);
    assert (&1.0f32).fuzzy_eq(&1.0f32);
    assert (&1.0f64).fuzzy_eq(&1.0f64);
}

#[test]
fn test_fuzzy_eq_eps() {
    assert (&1.2f).fuzzy_eq_eps(&0.9, &0.5);
    assert !(&1.5f).fuzzy_eq_eps(&0.9, &0.5);
}
<commit_msg>Convert fuzzy_epsilon constant to upper case and make public<commit_after>// Copyright 2012-2013 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.

#[forbid(deprecated_mode)];
//! Additional general-purpose comparison functionality.

use core::f32;
use core::f64;
use core::float;

pub const FUZZY_EPSILON: float = 1.0e-6;

pub trait FuzzyEq {
    pure fn fuzzy_eq(&self, other: &Self) -> bool;
    pure fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Self) -> bool;
}

impl float: FuzzyEq {
    pure fn fuzzy_eq(&self, other: &float) -> bool {
        self.fuzzy_eq_eps(other, &FUZZY_EPSILON)
    }

    pure fn fuzzy_eq_eps(&self, other: &float, epsilon: &float) -> bool {
        float::abs(*self - *other) < *epsilon
    }
}

impl f32: FuzzyEq {
    pure fn fuzzy_eq(&self, other: &f32) -> bool {
        self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f32))
    }

    pure fn fuzzy_eq_eps(&self, other: &f32, epsilon: &f32) -> bool {
        f32::abs(*self - *other) < *epsilon
    }
}

impl f64: FuzzyEq {
    pure fn fuzzy_eq(&self, other: &f64) -> bool {
        self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f64))
    }

    pure fn fuzzy_eq_eps(&self, other: &f64, epsilon: &f64) -> bool {
        f64::abs(*self - *other) < *epsilon
    }
}

#[test]
fn test_fuzzy_equals() {
    assert (&1.0f).fuzzy_eq(&1.0);
    assert (&1.0f32).fuzzy_eq(&1.0f32);
    assert (&1.0f64).fuzzy_eq(&1.0f64);
}

#[test]
fn test_fuzzy_eq_eps() {
    assert (&1.2f).fuzzy_eq_eps(&0.9, &0.5);
    assert !(&1.5f).fuzzy_eq_eps(&0.9, &0.5);
}
<|endoftext|>