<commit_before>extern crate symbolic_expressions;

use secsp::ast::*;
use self::symbolic_expressions::Sexp;

macro_rules! cil {
    ($x:expr) => {
        $x.into_sexp()
    }
}

macro_rules! cil_list {
    [ $( $x:expr ),* ] => {
        {
            let mut temp_vec : Vec<Sexp> = Vec::new();
            $(
                temp_vec.push($x.into());
            )*

            temp_vec.into()
        }
    };
}

pub trait ToCil: Sized + Clone {
    fn into_sexp(&self) -> Sexp;
}

pub trait CilType: TypeSpecifier {
    fn requires_initializer(&self) -> bool;
}

impl CilType for SymbolType {
    fn requires_initializer(&self) -> bool {
        match *self {
            SymbolType::Context => true,
            _ => false,
        }
    }
}

impl ToCil for Statement {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Statement::Declaration(ref decl) => decl.into_sexp(),
            Statement::MacroCall(ref id, ref params) => {
                let params_sexpr: Vec<Sexp> =
                    params.iter().map(|ref p: &Expr| p.into_sexp()).collect();

                cil_list!["call", id, params_sexpr]
            }
            Statement::IfElse {
                ref condition,
                ref then_block,
                ref else_ifs,
                ref else_block,
            } => {
                let mut statement_sexpr: Sexp = cil_list!["booleanif", condition.into_sexp()];
                let mut true_branch: Sexp = cil_list!["true"];
                for stmt in then_block {
                    true_branch.push(stmt.into_sexp());
                }

                statement_sexpr.push(true_branch);

                if let Some(ref else_body) = *else_block {
                    let mut else_branch: Sexp = cil_list!["false"];
                    for stmt in else_body {
                        else_branch.push(stmt.into_sexp());
                    }

                    statement_sexpr.push(else_branch);
                }

                statement_sexpr
            }
            _ => Sexp::Empty,
        }
    }
}

impl ToCil for BlockType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for SymbolType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for MacroParameter {
    fn into_sexp(&self) -> Sexp {
        cil_list![self.qualifier.into_sexp(), self.name.clone()]
    }
}

impl ToCil for Declaration {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Declaration::Block {
                ref is_abstract,
                ref qualifier,
                ref name,
                ref statements,
            } => {
                let mut statement: Sexp = cil_list![qualifier.into_sexp(), name];
                if *is_abstract {
                    let blockabstract_sexpr: Sexp = cil_list!["blockabstract", name];
                    statement.push(blockabstract_sexpr);
                }

                for stmt in statements {
                    statement.push(stmt.into_sexp());
                }

                statement
            }
            Declaration::Symbol {
                ref qualifier,
                ref name,
                ref initializer,
            } => {
                let mut declaration: Sexp = cil_list![qualifier.into_sexp(), name];

                if qualifier.requires_initializer() {
                    if let Some(ref expr) = *initializer {
                        declaration.push(expr.into_sexp());
                    } else {
                        //@todo - raise error
                    }
                }

                declaration
            }
            Declaration::Macro {
                ref name,
                ref parameters,
                ref statements,
            } => {
                let params: Vec<Sexp> = parameters.iter().map(|it| it.into_sexp()).collect();
                let mut decl: Sexp = cil_list!["macro", name, params];

                for stmt in statements {
                    decl.push(stmt.into_sexp());
                }

                decl
            }

            _ => Sexp::Empty,
        }
    }
}

impl ToCil for Expr {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Expr::Binary(ref lhs, ref op, ref rhs) => {
                cil_list![cil!(op), cil!(lhs.as_ref()), cil!(rhs.as_ref())]
            }
            Expr::Unary(ref op, ref expr) => cil_list![cil!(op), cil!(expr.as_ref())],
            Expr::Variable(ref id) => id.into(),
            Expr::LevelRange(ref low, ref high) => cil_list![cil!(low), cil!(high)],
            Expr::Level {
                ref sensitivity,
                ref categories,
            } => {
                let categories_sexpr: Vec<Sexp> = cil_list![categories.into_sexp()];

                cil_list![sensitivity, categories_sexpr]
            }
            Expr::Context {
                ref user_id,
                ref role_id,
                ref type_id,
                ref level_range,
            } => {
                let mut context_sexp: Sexp = cil_list![user_id, type_id, role_id];

                if let Some(ref expr) = *level_range {
                    context_sexp.push(expr.as_ref().into_sexp());
                }

                context_sexp
            }
            _ => Sexp::Empty, //@TODO
        }
    }
}

impl ToCil for BinaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            BinaryOp::BitwiseAnd | BinaryOp::ConditionalAnd => "and",
            BinaryOp::BitwiseOr | BinaryOp::ConditionalOr => "or",
            BinaryOp::BitwiseXor | BinaryOp::ConditionalXor => "xor",
        };

        result.into()
    }
}

impl ToCil for UnaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            UnaryOp::ConditionalNot | UnaryOp::BitwiseNot => "not",
        };

        result.into()
    }
}

#[cfg(test)]
mod testing {

    use super::*;

    #[test]
    pub fn compile_block_decl() {
        let decl = Declaration::Block {
            is_abstract: false,
            qualifier: BlockType::Block,
            name: "my_block".to_string(),
            statements: vec![],
        };

        let expected: Sexp = cil_list!["block", "my_block"];
        let actual = decl.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_abstract_block_decl() {
        let decl = Declaration::Block {
            is_abstract: true,
            qualifier: BlockType::Block,
            name: "my_block".to_string(),
            statements: vec![],
        };

        let blockabstract: Sexp = cil_list!["blockabstract", "my_block"];
        let expected: Sexp = cil_list!["block", "my_block", blockabstract];
        let actual = decl.into_sexp();

        assert_eq!(expected, actual);
    }
}<commit_msg>Add tests around compiling conditional expressions<commit_after>extern crate symbolic_expressions;

use secsp::ast::*;
use self::symbolic_expressions::Sexp;

macro_rules! cil {
    ($x:expr) => {
        $x.into_sexp()
    }
}

macro_rules! cil_list {
    [ $( $x:expr ),* ] => {
        {
            let mut temp_vec : Vec<Sexp> = Vec::new();
            $(
                temp_vec.push($x.into());
            )*

            let sexp : Sexp = temp_vec.into();
            sexp
        }
    };
}

pub trait ToCil: Sized + Clone {
    fn into_sexp(&self) -> Sexp;
}

pub trait CilType: TypeSpecifier {
    fn requires_initializer(&self) -> bool;
}

impl CilType for SymbolType {
    fn requires_initializer(&self) -> bool {
        match *self {
            SymbolType::Context => true,
            _ => false,
        }
    }
}

impl ToCil for Statement {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Statement::Declaration(ref decl) => decl.into_sexp(),
            Statement::MacroCall(ref id, ref params) => {
                let params_sexpr: Vec<Sexp> =
                    params.iter().map(|ref p: &Expr| p.into_sexp()).collect();

                cil_list!["call", id, params_sexpr]
            }
            Statement::IfElse {
                ref condition,
                ref then_block,
                ref else_ifs,
                ref else_block,
            } => {
                let mut statement_sexpr: Sexp = cil_list!["booleanif", condition.into_sexp()];
                let mut true_branch: Sexp = cil_list!["true"];
                for stmt in then_block {
                    true_branch.push(stmt.into_sexp());
                }

                statement_sexpr.push(true_branch);

                if let Some(ref else_body) = *else_block {
                    let mut else_branch: Sexp = cil_list!["false"];
                    for stmt in else_body {
                        else_branch.push(stmt.into_sexp());
                    }

                    statement_sexpr.push(else_branch);
                }

                statement_sexpr
            }
            _ => Sexp::Empty,
        }
    }
}

impl ToCil for BlockType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for SymbolType {
    fn into_sexp(&self) -> Sexp {
        self.to_cil().into()
    }
}

impl ToCil for MacroParameter {
    fn into_sexp(&self) -> Sexp {
        cil_list![self.qualifier.into_sexp(), self.name.clone()]
    }
}

impl ToCil for Declaration {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Declaration::Block {
                ref is_abstract,
                ref qualifier,
                ref name,
                ref statements,
            } => {
                let mut statement: Sexp = cil_list![qualifier.into_sexp(), name];
                if *is_abstract {
                    let blockabstract_sexpr: Sexp = cil_list!["blockabstract", name];
                    statement.push(blockabstract_sexpr);
                }

                for stmt in statements {
                    statement.push(stmt.into_sexp());
                }

                statement
            }
            Declaration::Symbol {
                ref qualifier,
                ref name,
                ref initializer,
            } => {
                let mut declaration: Sexp = cil_list![qualifier.into_sexp(), name];

                if qualifier.requires_initializer() {
                    if let Some(ref expr) = *initializer {
                        declaration.push(expr.into_sexp());
                    } else {
                        //@todo - raise error
                    }
                }

                declaration
            }
            Declaration::Macro {
                ref name,
                ref parameters,
                ref statements,
            } => {
                let params: Vec<Sexp> = parameters.iter().map(|it| it.into_sexp()).collect();
                let mut decl: Sexp = cil_list!["macro", name, params];

                for stmt in statements {
                    decl.push(stmt.into_sexp());
                }

                decl
            }

            _ => Sexp::Empty,
        }
    }
}

impl ToCil for Expr {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Expr::Binary(ref lhs, ref op, ref rhs) => {
                cil_list![cil!(op), cil!(lhs.as_ref()), cil!(rhs.as_ref())]
            }
            Expr::Unary(ref op, ref expr) => cil_list![cil!(op), cil!(expr.as_ref())],
            Expr::Variable(ref id) => id.into(),
            Expr::LevelRange(ref low, ref high) => cil_list![cil!(low), cil!(high)],
            Expr::Level {
                ref sensitivity,
                ref categories,
            } => {
                let categories_sexpr: Sexp = cil_list![categories.into_sexp()];

                cil_list![sensitivity, categories_sexpr]
            }
            Expr::Context {
                ref user_id,
                ref role_id,
                ref type_id,
                ref level_range,
            } => {
                let mut context_sexp: Sexp = cil_list![user_id, type_id, role_id];

                if let Some(ref expr) = *level_range {
                    context_sexp.push(expr.as_ref().into_sexp());
                }

                context_sexp
            }
            _ => Sexp::Empty, //@TODO
        }
    }
}

impl ToCil for BinaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            BinaryOp::BitwiseAnd | BinaryOp::ConditionalAnd => "and",
            BinaryOp::BitwiseOr | BinaryOp::ConditionalOr => "or",
            BinaryOp::BitwiseXor | BinaryOp::ConditionalXor => "xor",
        };

        result.into()
    }
}

impl ToCil for UnaryOp {
    fn into_sexp(&self) -> Sexp {
        let result = match *self {
            UnaryOp::ConditionalNot | UnaryOp::BitwiseNot => "not",
        };

        result.into()
    }
}

#[cfg(test)]
mod testing {

    use super::*;

    #[test]
    pub fn compile_block_decl() {
        let decl = Declaration::Block {
            is_abstract: false,
            qualifier: BlockType::Block,
            name: "my_block".to_string(),
            statements: vec![],
        };

        let expected: Sexp = cil_list!["block", "my_block"];
        let actual = decl.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_abstract_block_decl() {
        let decl = Declaration::Block {
            is_abstract: true,
            qualifier: BlockType::Block,
            name: "my_block".to_string(),
            statements: vec![],
        };

        let blockabstract: Sexp = cil_list!["blockabstract", "my_block"];
        let expected: Sexp = cil_list!["block", "my_block", blockabstract];
        let actual = decl.into_sexp();

        assert_eq!(expected, actual);
    }

    #[test]
    pub fn compile_conditional_exprs() {
        let inputs = vec![
            Expr::Binary(
                Box::from(Expr::var("a")),
                BinaryOp::ConditionalAnd,
                Box::from(Expr::Unary(
                    UnaryOp::ConditionalNot,
                    Box::from(Expr::var("b")),
                ))
            ),
            Expr::Binary(
                Box::from(Expr::var("a")),
                BinaryOp::ConditionalOr,
                Box::from(Expr::Binary(
                    Box::from(Expr::var("b")),
                    BinaryOp::ConditionalXor,
                    Box::from(Expr::var("c")),
                ))
            ),
        ];

        let expectations = vec![
            cil_list!["and", "a", cil_list!["not", "b"]],
            cil_list!["or", "a", cil_list!["xor", "b", "c"]],
        ];

        for id in 0..inputs.len() {
            let input = &inputs[0];
            let expected = &expectations[0];
            let actual = input.into_sexp();

            assert_eq!(expected, &actual);
        }
    }
}<|endoftext|>


<commit_before>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
             -> Result<Response, Box<Show>>
    {
        res
    }
}

pub trait AroundMiddleware : Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Share>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Share>>,
    handler: Option<Box<Handler + Send + Share>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler + Send + Share>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + Send + Share>)
        }
    }

    pub fn add<M: Middleware + Send + Share>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + Send + Share>);
    }

    pub fn around<M: AroundMiddleware + Send + Share>(&mut self,
                                                         mut middleware: M) {
        let handler = self.handler.take_unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + Send + Share>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.get_ref().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show>>)
                  -> Result<Response, Box<Show>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use super::*;

    use std::any::{Any, AnyRefExt};
    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions, Handler};

    struct RequestSentinel {
        path: String,
        extensions: HashMap<&'static str, Box<Any>>,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show>> {
            req.mut_extensions().insert("test.middleware", box "hello".to_str() as Box<Any>);
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(e).to_str().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
            Err(box "Nope".to_str() as Box<Show>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Share>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Share>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
            req.mut_extensions().insert("test.round-and-round", box "hello".to_str() as Box<Any>);
            self.handler.get_ref().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request, key: &'static str) -> &'a T {
        req.extensions().find(&key).and_then(|s| s.as_ref::<T>())
            .expect(format!("No {} key found in extensions", key).as_slice())
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_str())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        let middle = get_extension::<String>(req, "test.round-and-round");

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello".to_str());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_str().ok().expect("No body"), "Error in handler".to_str());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello hello".to_str());
    }
}
<commit_msg>Remove unnecessary bounds, require Send+Share for middleware<commit_after>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Share {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
             -> Result<Response, Box<Show>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Share>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Share>>,
    handler: Option<Box<Handler + Send + Share>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + Send + Share>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + Send + Share>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take_unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + Send + Share>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.get_ref().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show>>)
                  -> Result<Response, Box<Show>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use super::*;

    use std::any::{Any, AnyRefExt};
    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions, Handler};

    struct RequestSentinel {
        path: String,
        extensions: HashMap<&'static str, Box<Any>>,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show>> {
            req.mut_extensions().insert("test.middleware", box "hello".to_str() as Box<Any>);
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(e).to_str().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
            Err(box "Nope".to_str() as Box<Show>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Share>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Share>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
            req.mut_extensions().insert("test.round-and-round", box "hello".to_str() as Box<Any>);
            self.handler.get_ref().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request, key: &'static str) -> &'a T {
        req.extensions().find(&key).and_then(|s| s.as_ref::<T>())
            .expect(format!("No {} key found in extensions", key).as_slice())
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_str())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        let middle = get_extension::<String>(req, "test.round-and-round");

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello".to_str());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_str().ok().expect("No body"), "Error in handler".to_str());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello hello".to_str());
    }
}
<|endoftext|>


<commit_before>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import layers::*;
import scene::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{DOUBLE, check_loop, create_window, destroy_window, display_func, init};
import glut::{init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::{builder, get_opts, run_listener, set_opts};

class Renderer {
    let image: @Image;
    let mut image_layer: @ImageLayer;
    let mut t: f32;
    let mut delta: f32;
    let mut render_context: option<RenderContext>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        self.image = @Image(cairo_image.width() as uint, cairo_image.height() as uint, RGB24Format,
                            convert_rgb32_to_rgb24(cairo_image.data()));
        io::println(#fmt("image is %ux%u", self.image.width, self.image.height));

        self.image_layer = @ImageLayer(self.image);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        alt self.render_context {
            none {
                self.render_context = some(init_render_context());
            }
            some(_) {
                // Nothing to do.
            }
        }
        let context = alt self.render_context {
            none { fail }
            some(ctx) { ctx }
        };

        let t = self.t;
        self.image_layer.common.transform = Matrix4(400.0f32 * t, 0.0f32,       0.0f32, 0.0f32,
                                                    0.0f32,       300.0f32 * t, 0.0f32, 0.0f32,
                                                    0.0f32,       0.0f32,       1.0f32, 0.0f32,
                                                    0.0f32,       0.0f32,       0.0f32, 1.0f32);

        let mut scene = Scene(ImageLayerKind(self.image_layer), Size2D(400.0f32, 300.0f32));
        render_scene(context, scene);

        self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = builder();
    let opts = {
        sched: some({ mode: task::osmain, foreign_stack_size: none })
        with get_opts(builder)
    };
    set_opts(builder, opts);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = do run_listener(builder) |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(DOUBLE as c_uint);
        let window = create_window(~"Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(2500) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<commit_msg>Change rust-layers test.rs to new task::task_builder interface<commit_after>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import layers::*;
import scene::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{DOUBLE, check_loop, create_window, destroy_window, display_func, init};
import glut::{init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::{task_builder, get_opts, run_listener, set_opts};

class Renderer {
    let image: @Image;
    let mut image_layer: @ImageLayer;
    let mut t: f32;
    let mut delta: f32;
    let mut render_context: option<RenderContext>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        self.image = @Image(cairo_image.width() as uint, cairo_image.height() as uint, RGB24Format,
                            convert_rgb32_to_rgb24(cairo_image.data()));
        io::println(#fmt("image is %ux%u", self.image.width, self.image.height));

        self.image_layer = @ImageLayer(self.image);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        alt self.render_context {
            none {
                self.render_context = some(init_render_context());
            }
            some(_) {
                // Nothing to do.
            }
        }
        let context = alt self.render_context {
            none { fail }
            some(ctx) { ctx }
        };

        let t = self.t;
        self.image_layer.common.transform = Matrix4(400.0f32 * t, 0.0f32,       0.0f32, 0.0f32,
                                                    0.0f32,       300.0f32 * t, 0.0f32, 0.0f32,
                                                    0.0f32,       0.0f32,       1.0f32, 0.0f32,
                                                    0.0f32,       0.0f32,       0.0f32, 1.0f32);

        let mut scene = Scene(ImageLayerKind(self.image_layer), Size2D(400.0f32, 300.0f32));
        render_scene(context, scene);

        self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::osmain);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = do builder.spawn_listener |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(DOUBLE as c_uint);
        let window = create_window(~"Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(2500) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<|endoftext|>


<commit_before>use crate::utils::deserialize::deserialize_opt_duration;
use cosmogony::ZoneType;
use geojson::{GeoJson, Geometry};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::time::Duration;

use crate::adapters::primary::common::coord::Coord;
use crate::adapters::primary::common::filters::Filters;
use common::document::ContainerDocument;
use places::{addr::Addr, admin::Admin, poi::Poi, stop::Stop, street::Street};

pub const DEFAULT_LIMIT_RESULT_ES: i64 = 10;

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ForwardGeocoderExplainQuery {
    pub doc_id: String,
    pub doc_type: String,

    #[serde(flatten)]
    pub query: ForwardGeocoderQuery,
}

/// This structure contains all the query parameters that
/// can be submitted for the autocomplete endpoint.
///
/// Only the `q` parameter is mandatory.
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ForwardGeocoderQuery {
    pub q: String,
    pub lat: Option<f32>,
    pub lon: Option<f32>,
    pub shape_scope: Option<Vec<Type>>,
    #[serde(default, rename = "type")]
    pub types: Option<Vec<Type>>,
    #[serde(default, rename = "zone_type")]
    pub zone_types: Option<Vec<ZoneType>>,
    pub poi_types: Option<Vec<String>>,
    #[serde(default = "default_result_limit")]
    pub limit: i64,
    #[serde(deserialize_with = "deserialize_opt_duration", default)]
    pub timeout: Option<Duration>,
    pub pt_dataset: Option<Vec<String>>,
    pub poi_dataset: Option<Vec<String>>,
    pub request_id: Option<String>,
    pub proximity_scale: Option<f64>,
    pub proximity_offset: Option<f64>,
    pub proximity_decay: Option<f64>,
}

fn default_result_limit() -> i64 {
    DEFAULT_LIMIT_RESULT_ES
}

impl From<(ForwardGeocoderQuery, Option<Geometry>)> for Filters {
    fn from(source: (ForwardGeocoderQuery, Option<Geometry>)) -> Self {
        let (query, geometry) = source;
        let zone_types = zone_types.map(|zts| zts.iter().map(|t| t.as_str().to_string()).collect());
        Filters {
            // When option_zip_option becomes available: coord: input.lat.zip_with(input.lon, Coord::new),
            coord: match (query.lat, query.lon) {
                (Some(lat), Some(lon)) => Some(Coord::new(lat, lon)),
                _ => None,
            },
            shape: geometry.map(|geometry| {
                (
                    geometry,
                    query
                        .shape_scope
                        .map(|shape_scope| {
                            shape_scope.iter().map(|t| t.as_str().to_string()).collect()
                        })
                        .unwrap_or_else(|| {
                            vec![
                                Type::House,
                                Type::Poi,
                                Type::StopArea,
                                Type::Street,
                                Type::Zone,
                            ]
                            .iter()
                            .map(|t| t.as_str().to_string())
                            .collect()
                        }),
                )
            }),
            zone_types,
            poi_types: query.poi_types,
            limit: query.limit,
            timeout: query.timeout,
            proximity_scale: query.proximity_scale,
            proximity_offset: query.proximity_offset,
            proximity_decay: query.proximity_decay,
        }
    }
}

/// This structure contains all the query parameters that
/// can be submitted for the reverse endpoint.
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ReverseGeocoderQuery {
    pub lat: f64,
    pub lon: f64,
    #[serde(default = "default_result_limit")]
    pub limit: i64,
    #[serde(deserialize_with = "deserialize_opt_duration")]
    pub timeout: Option<Duration>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JsonParam {
    pub shape: GeoJson,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ExplainResponseBody {
    pub explanation: JsonValue,
}

impl From<JsonValue> for ExplainResponseBody {
    fn from(explanation: JsonValue) -> Self {
        ExplainResponseBody { explanation }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct BragiStatus {
    pub version: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct MimirStatus {
    pub version: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ElasticsearchStatus {
    pub version: String,
    pub health: String,
    pub url: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct StatusResponseBody {
    pub bragi: BragiStatus,
    pub mimir: MimirStatus,
    pub elasticsearch: ElasticsearchStatus,
}

/// This macro is used to define the forward_geocoder route.
/// It takes a client (ElasticsearchStorage) and query settings
/// It can be either a GET request, with query parameters,
/// or a POST request, with both query parameters and a GeoJson shape
/// in the body.
#[macro_export]
macro_rules! forward_geocoder {
    ($cl:expr, $st:expr) => {
        routes::forward_geocoder_get()
            .or(routes::forward_geocoder_post())
            .unify()
            .and(routes::with_client($cl))
            .and(routes::with_settings($st))
            .and_then(handlers::forward_geocoder)
    };
}

pub use forward_geocoder;

#[macro_export]
macro_rules! forward_geocoder_explain {
    ($cl:expr, $st:expr) => {
        routes::forward_geocoder_explain_get()
            .or(routes::forward_geocoder_explain_post())
            .unify()
            .and(routes::with_client($cl))
            .and(routes::with_settings($st))
            .and_then(handlers::forward_geocoder_explain)
    };
}
pub use forward_geocoder_explain;

#[macro_export]
macro_rules! reverse_geocoder {
    ($cl:expr, $st:expr) => {
        routes::reverse_geocoder()
            .and(routes::with_client($cl))
            .and(routes::with_settings($st))
            .and_then(handlers::reverse_geocoder)
    };
}
pub use reverse_geocoder;

#[macro_export]
macro_rules! status {
    ($cl:expr, $es:expr) => {
        routes::status()
            .and(routes::with_client($cl))
            .and(routes::with_elasticsearch($es))
            .and_then(handlers::status)
    };
}
pub use status;

#[derive(PartialEq, Copy, Clone, Debug, Deserialize, Serialize)]
pub enum Type {
    #[serde(rename = "house")]
    House,
    #[serde(rename = "poi")]
    Poi,
    #[serde(rename = "public_transport:stop_area")]
    StopArea,
    #[serde(rename = "street")]
    Street,
    #[serde(rename = "zone")]
    Zone,
}

impl Type {
    pub fn as_str(&self) -> &'static str {
        match self {
            Type::House => "house",
            Type::Poi => "poi",
            Type::StopArea => "public_transport:stop_area",
            Type::Street => "street",
            Type::Zone => "zone",
        }
    }

    pub fn as_index_type(&self) -> &'static str {
        match self {
            Type::House => Addr::static_doc_type(),
            Type::Poi => Poi::static_doc_type(),
            Type::StopArea => Stop::static_doc_type(),
            Type::Street => Street::static_doc_type(),
            Type::Zone => Admin::static_doc_type(),
        }
    }
}
<commit_msg>fix rebase<commit_after>use crate::utils::deserialize::deserialize_opt_duration;
use cosmogony::ZoneType;
use geojson::{GeoJson, Geometry};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::time::Duration;

use crate::adapters::primary::common::coord::Coord;
use crate::adapters::primary::common::filters::Filters;
use common::document::ContainerDocument;
use places::{addr::Addr, admin::Admin, poi::Poi, stop::Stop, street::Street};

pub const DEFAULT_LIMIT_RESULT_ES: i64 = 10;

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ForwardGeocoderExplainQuery {
    pub doc_id: String,
    pub doc_type: String,

    #[serde(flatten)]
    pub query: ForwardGeocoderQuery,
}

/// This structure contains all the query parameters that
/// can be submitted for the autocomplete endpoint.
///
/// Only the `q` parameter is mandatory.
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ForwardGeocoderQuery {
    pub q: String,
    pub lat: Option<f32>,
    pub lon: Option<f32>,
    pub shape_scope: Option<Vec<Type>>,
    #[serde(default, rename = "type")]
    pub types: Option<Vec<Type>>,
    #[serde(default, rename = "zone_type")]
    pub zone_types: Option<Vec<ZoneType>>,
    pub poi_types: Option<Vec<String>>,
    #[serde(default = "default_result_limit")]
    pub limit: i64,
    #[serde(deserialize_with = "deserialize_opt_duration", default)]
    pub timeout: Option<Duration>,
    pub pt_dataset: Option<Vec<String>>,
    pub poi_dataset: Option<Vec<String>>,
    pub request_id: Option<String>,
    pub proximity_scale: Option<f64>,
    pub proximity_offset: Option<f64>,
    pub proximity_decay: Option<f64>,
}

fn default_result_limit() -> i64 {
    DEFAULT_LIMIT_RESULT_ES
}

impl From<(ForwardGeocoderQuery, Option<Geometry>)> for Filters {
    fn from(source: (ForwardGeocoderQuery, Option<Geometry>)) -> Self {
        let (query, geometry) = source;
        let zone_types = query
            .zone_types
            .map(|zts| zts.iter().map(|t| t.as_str().to_string()).collect());
        Filters {
            // When option_zip_option becomes available: coord: input.lat.zip_with(input.lon, Coord::new),
            coord: match (query.lat, query.lon) {
                (Some(lat), Some(lon)) => Some(Coord::new(lat, lon)),
                _ => None,
            },
            shape: geometry.map(|geometry| {
                (
                    geometry,
                    query
                        .shape_scope
                        .map(|shape_scope| {
                            shape_scope.iter().map(|t| t.as_str().to_string()).collect()
                        })
                        .unwrap_or_else(|| {
                            vec![
                                Type::House,
                                Type::Poi,
                                Type::StopArea,
                                Type::Street,
                                Type::Zone,
                            ]
                            .iter()
                            .map(|t| t.as_str().to_string())
                            .collect()
                        }),
                )
            }),
            zone_types,
            poi_types: query.poi_types,
            limit: query.limit,
            timeout: query.timeout,
            proximity_scale: query.proximity_scale,
            proximity_offset: query.proximity_offset,
            proximity_decay: query.proximity_decay,
        }
    }
}

/// This structure contains all the query parameters that
/// can be submitted for the reverse endpoint.
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ReverseGeocoderQuery {
    pub lat: f64,
    pub lon: f64,
    #[serde(default = "default_result_limit")]
    pub limit: i64,
    #[serde(deserialize_with = "deserialize_opt_duration")]
    pub timeout: Option<Duration>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JsonParam {
    pub shape: GeoJson,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ExplainResponseBody {
    pub explanation: JsonValue,
}

impl From<JsonValue> for ExplainResponseBody {
    fn from(explanation: JsonValue) -> Self {
        ExplainResponseBody { explanation }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct BragiStatus {
    pub version: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct MimirStatus {
    pub version: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct ElasticsearchStatus {
    pub version: String,
    pub health: String,
    pub url: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct StatusResponseBody {
    pub bragi: BragiStatus,
    pub mimir: MimirStatus,
    pub elasticsearch: ElasticsearchStatus,
}

/// This macro is used to define the forward_geocoder route.
/// It takes a client (ElasticsearchStorage) and query settings
/// It can be either a GET request, with query parameters,
/// or a POST request, with both query parameters and a GeoJson shape
/// in the body.
#[macro_export]
macro_rules! forward_geocoder {
    ($cl:expr, $st:expr) => {
        routes::forward_geocoder_get()
            .or(routes::forward_geocoder_post())
            .unify()
            .and(routes::with_client($cl))
            .and(routes::with_settings($st))
            .and_then(handlers::forward_geocoder)
    };
}

pub use forward_geocoder;

#[macro_export]
macro_rules! forward_geocoder_explain {
    ($cl:expr, $st:expr) => {
        routes::forward_geocoder_explain_get()
            .or(routes::forward_geocoder_explain_post())
            .unify()
            .and(routes::with_client($cl))
            .and(routes::with_settings($st))
            .and_then(handlers::forward_geocoder_explain)
    };
}
pub use forward_geocoder_explain;

#[macro_export]
macro_rules! reverse_geocoder {
    ($cl:expr, $st:expr) => {
        routes::reverse_geocoder()
            .and(routes::with_client($cl))
            .and(routes::with_settings($st))
            .and_then(handlers::reverse_geocoder)
    };
}
pub use reverse_geocoder;

#[macro_export]
macro_rules! status {
    ($cl:expr, $es:expr) => {
        routes::status()
            .and(routes::with_client($cl))
            .and(routes::with_elasticsearch($es))
            .and_then(handlers::status)
    };
}
pub use status;

#[derive(PartialEq, Copy, Clone, Debug, Deserialize, Serialize)]
pub enum Type {
    #[serde(rename = "house")]
    House,
    #[serde(rename = "poi")]
    Poi,
    #[serde(rename = "public_transport:stop_area")]
    StopArea,
    #[serde(rename = "street")]
    Street,
    #[serde(rename = "zone")]
    Zone,
}

impl Type {
    pub fn as_str(&self) -> &'static str {
        match self {
            Type::House => "house",
            Type::Poi => "poi",
            Type::StopArea => "public_transport:stop_area",
            Type::Street => "street",
            Type::Zone => "zone",
        }
    }

    pub fn as_index_type(&self) -> &'static str {
        match self {
            Type::House => Addr::static_doc_type(),
            Type::Poi => Poi::static_doc_type(),
            Type::StopArea => Stop::static_doc_type(),
            Type::Street => Street::static_doc_type(),
            Type::Zone => Admin::static_doc_type(),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(phase, macro_rules)]
#![deny(unused)]

extern crate serialize;
#[phase(plugin, link)] extern crate log;

extern crate cargo;

use std::collections::TreeSet;
use std::os;
use std::io;
use std::io::fs::{mod, PathExtensions};
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult};

#[deriving(Decodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand( ($macro:ident) => ({
    $macro!(bench)
    $macro!(build)
    $macro!(clean)
    $macro!(config_for_key)
    $macro!(config_list)
    $macro!(doc)
    $macro!(fetch)
    $macro!(generate_lockfile)
    $macro!(git_checkout)
    $macro!(help)
    $macro!(locate_project)
    $macro!(login)
    $macro!(new)
    $macro!(owner)
    $macro!(package)
    $macro!(pkgid)
    $macro!(publish)
    $macro!(read_manifest)
    $macro!(run)
    $macro!(test)
    $macro!(update)
    $macro!(verify_project)
    $macro!(version)
    $macro!(yank)
}) )

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo; args={}", os::args());
    shell.set_verbose(flags.flag_verbose);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let (mut args, command) = match flags.arg_command.as_slice() {
        "" | "help" if flags.arg_args.len() == 0 => {
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin(execute, shell, USAGE,
                                                   ["-h".to_string()], false);
            cargo::process_executed(r, shell);
            return Ok(None)
        }
        "help" if flags.arg_args[0].as_slice() == "-h" ||
                  flags.arg_args[0].as_slice() == "--help" =>
            (flags.arg_args, "help"),
        "help" => (vec!["-h".to_string()], flags.arg_args[0].as_slice()),
        s => (flags.arg_args.clone(), s),
    };
    args.insert(0, command.to_string());
    args.insert(0, os::args()[0].clone());

    macro_rules! cmd( ($name:ident) => (
        if command.as_slice() == stringify!($name).replace("_", "-").as_slice() {
            mod $name;
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, shell,
                                                   $name::USAGE,
                                                   args.as_slice(),
                                                   false);
            cargo::process_executed(r, shell);
            return Ok(None)
        }
    ) )
    each_subcommand!(cmd)

    execute_subcommand(command.as_slice(), args.as_slice(), shell);
    Ok(None)
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => return handle_error(CliError::new("No such subcommand", 127),
                                    shell)
    };
    let status = Command::new(command)
                         .args(args)
                         .stdin(InheritFd(0))
                         .stdout(InheritFd(1))
                         .stderr(InheritFd(2))
                         .status();

    match status {
        Ok(ExitStatus(0)) => (),
        Ok(ExitStatus(i)) => {
            handle_error(CliError::new("", i as uint), shell)
        }
        Ok(ExitSignal(i)) => {
            let msg = format!("subcommand failed with signal: {}", i);
            handle_error(CliError::new(msg, i as uint), shell)
        }
        Err(io::IoError{kind, ..}) if kind == io::FileNotFound =>
            handle_error(CliError::new("No such subcommand", 127), shell),
        Err(err) => handle_error(
            CliError::new(
                format!("Subcommand failed to run: {}", err), 127),
            shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> TreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = TreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(os::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = filename.slice(
                    command_prefix.len(),
                    filename.len() - os::consts::EXE_SUFFIX.len());
                commands.insert(String::from_str(command));
            }
        }
    }

    macro_rules! add_cmd( ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) )
    each_subcommand!(add_cmd);
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(io::FileStat{ kind: io::TypeFile, perm, ..}) =>
            perm.contains(io::OTHER_EXECUTE),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(command_exe.as_slice()));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    match os::self_exe_path() {
        Some(path) => {
            dirs.push(path.join("../lib/cargo"));
            dirs.push(path);
        },
        None => {}
    };
    match std::os::getenv("PATH") {
        Some(val) => {
            for dir in os::split_paths(val).iter() {
                dirs.push(Path::new(dir))
            }
        },
        None => {}
    };
    dirs
}
<commit_msg>Fix infinite recursion when invoked without args<commit_after>#![feature(phase, macro_rules)]
#![deny(unused)]

extern crate serialize;
#[phase(plugin, link)] extern crate log;

extern crate cargo;

use std::collections::TreeSet;
use std::os;
use std::io;
use std::io::fs::{mod, PathExtensions};
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult};

#[deriving(Decodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand( ($macro:ident) => ({
    $macro!(bench)
    $macro!(build)
    $macro!(clean)
    $macro!(config_for_key)
    $macro!(config_list)
    $macro!(doc)
    $macro!(fetch)
    $macro!(generate_lockfile)
    $macro!(git_checkout)
    $macro!(help)
    $macro!(locate_project)
    $macro!(login)
    $macro!(new)
    $macro!(owner)
    $macro!(package)
    $macro!(pkgid)
    $macro!(publish)
    $macro!(read_manifest)
    $macro!(run)
    $macro!(test)
    $macro!(update)
    $macro!(verify_project)
    $macro!(version)
    $macro!(yank)
}) )

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo; args={}", os::args());
    shell.set_verbose(flags.flag_verbose);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let (mut args, command) = match flags.arg_command.as_slice() {
        "" | "help" if flags.arg_args.len() == 0 => {
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin(execute, shell, USAGE,
                                                   [os::args()[0].clone(), "-h".to_string()], false);
            cargo::process_executed(r, shell);
            return Ok(None)
        }
        "help" if flags.arg_args[0].as_slice() == "-h" ||
                  flags.arg_args[0].as_slice() == "--help" =>
            (flags.arg_args, "help"),
        "help" => (vec!["-h".to_string()], flags.arg_args[0].as_slice()),
        s => (flags.arg_args.clone(), s),
    };
    args.insert(0, command.to_string());
    args.insert(0, os::args()[0].clone());

    macro_rules! cmd( ($name:ident) => (
        if command.as_slice() == stringify!($name).replace("_", "-").as_slice() {
            mod $name;
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, shell,
                                                   $name::USAGE,
                                                   args.as_slice(),
                                                   false);
            cargo::process_executed(r, shell);
            return Ok(None)
        }
    ) )
    each_subcommand!(cmd)

    execute_subcommand(command.as_slice(), args.as_slice(), shell);
    Ok(None)
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => return handle_error(CliError::new("No such subcommand", 127),
                                    shell)
    };
    let status = Command::new(command)
                         .args(args)
                         .stdin(InheritFd(0))
                         .stdout(InheritFd(1))
                         .stderr(InheritFd(2))
                         .status();

    match status {
        Ok(ExitStatus(0)) => (),
        Ok(ExitStatus(i)) => {
            handle_error(CliError::new("", i as uint), shell)
        }
        Ok(ExitSignal(i)) => {
            let msg = format!("subcommand failed with signal: {}", i);
            handle_error(CliError::new(msg, i as uint), shell)
        }
        Err(io::IoError{kind, ..}) if kind == io::FileNotFound =>
            handle_error(CliError::new("No such subcommand", 127), shell),
        Err(err) => handle_error(
            CliError::new(
                format!("Subcommand failed to run: {}", err), 127),
            shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> TreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = TreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(os::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = filename.slice(
                    command_prefix.len(),
                    filename.len() - os::consts::EXE_SUFFIX.len());
                commands.insert(String::from_str(command));
            }
        }
    }

    macro_rules! add_cmd( ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) )
    each_subcommand!(add_cmd);
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(io::FileStat{ kind: io::TypeFile, perm, ..}) =>
            perm.contains(io::OTHER_EXECUTE),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(command_exe.as_slice()));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    match os::self_exe_path() {
        Some(path) => {
            dirs.push(path.join("../lib/cargo"));
            dirs.push(path);
        },
        None => {}
    };
    match std::os::getenv("PATH") {
        Some(val) => {
            for dir in os::split_paths(val).iter() {
                dirs.push(Path::new(dir))
            }
        },
        None => {}
    };
    dirs
}
<|endoftext|>


<commit_before>/// Implements the block_add procedure

/*

Block storing is a tricky part; blocks are stored in the spent-tree and referenced in the
 hash-index

 This can go out of order:  For instance consider 5 blocks added in the order A, B, D, E, C
 (for this pseudocode, each block has the previous letter as prev_block_hash)

 We show the some pseudocode for actions on hashindex (hi) and spent-tree (st),
 for the insertion of this sequence

 insert A:
    st.store_block(A)
    fn do_connect(null,A) =
      (prev = null, no get_or_set)
      hi.set(A)

 insert B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
      hi.set(B)

 insert D:
    st.store_block(D)
    hi.get_or_set(C, guard[D]) return none & adds guard[D] at hash C

 insert E:
   st.store_block(E)
   hi.get_or_set(D, guard[E]) return none & adds guard[E] at hash D

 insert C:
   st.store_block(C)
   hi.get_or_set(B, guard[C]) returns B
   fn do_connect(B,C) =
      st.connect_block(B,C)
      hi.set(C) -> fail due to guard([D])

        loop {
            hi.get(C) -> return guard[D]
            do_connect(C,D)
            hi.set(C, guard([D]) -> fail or break
        }

  Now let us consider what happens when C' is inserted *during* processing of B. Copyied from B above:
  B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
        < here C' is inserted as B -> guard[C']
      hi.set(B) -> fail due to guard[C']
      loop {
            hi.get(B) -> return guard[C']
            do_connect(B,C')
            hi.set(B, guard([C']) -> success!
        }

*/

use hash::*;
use util::*;
use buffer::*;
use rayon::prelude::*;
use slog ;

use store::Store;
use transaction;
use merkle_tree;
use block::*;
use store::Record;
use store::BlockPtr;
use store::HashIndexGuard;

type BlockResult<T> = Result<T, BlockError>;

// minimum number of hashes to use parallel hashing
const PARALLEL_HASHING_THRESHOLD: usize = 40;

/// Returns true if the given hash is the hash of a genesis block
fn is_genesis_block(hash: Hash32) -> bool {
    const HASH_GENESIS: &'static str =
        "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";

    let genesis = Hash32Buf::from_slice(&from_hex_rev(HASH_GENESIS));

    genesis.as_ref() == hash
}

// Connects two blocks (A,B) in the spent-tree and then stores the hash of B in the hash-index
// Connecting the blocks will verify double-spents
//
// It can be that another block C is also waiting for B; this will trigger their connection (B,C) too
// and maybe (C,D)... etcetera
//
// This would be neat to do recursively, but this could exhaust the stack , we use a loop with
// a to_do for connections.
fn connect_block(
    store:           &mut Store,
    this_block_hash: Hash32,
    previous_block:  Option<BlockPtr>,
    this_block:      BlockPtr)

    -> BlockResult<()>
{
    trace!(store.logger, "Connect block";
        "this_hash"  =>  format!("{:?}", this_block_hash),
        "prev_end"   =>  format!("{:?}", previous_block),
        "this_start" =>  format!("{:?}", this_block)
    );

    // we lay connections between the end of one block and the start of this_block
    // prev_end is None only for genesis
    #[derive(Debug)]
    struct Connection {
        block:         BlockPtr,
        block_hash:    Hash32Buf,
        solved_guards: Vec<BlockPtr>
    }

    // connect first block ...
    if let Some(previous_block) = previous_block {
        store.spent_tree.connect_block( &mut store.spent_index, & store.logger, previous_block, this_block) ?;
    }

    // The to_do list contains blocks that are connected to their previous but not yet added to the
    // block-index.
    let mut todo = vec![Connection {
        block:         this_block,
        block_hash:    this_block_hash.as_buf(),
        solved_guards: vec![]
    }];

    while let Some(conn) = todo.pop() {

        trace!(store.logger, "Connect block - set-hash-loop";
            "conn"  => format!("{:?}",   conn));

        // if we can store this hash we can move to the next one
        if store.block_index.set(conn.block_hash.as_ref(), conn.block.to_non_guard(), &conn.solved_guards, false) {
            trace!(store.logger, "Connect block - set-hash-loop - ok");
            continue;
        }

        let guards = store.block_index.get(conn.block_hash.as_ref());

        if guards.iter().any(|ptr| !ptr.is_guard()) {
            // this is not a guard, this is _this_ block. It seems the block
            // was added by a concurrent user; will do fine.
            trace!(store.logger, "Connect block - set-hash-loop - concurrent add");
            continue;
        }

        //let guards = store.hash_index.get(conn.this_hash);
        todo.push(Connection {
            block: conn.block,
            block_hash: conn.block_hash,
            solved_guards: guards.clone()
        });

        //let guards = store.hash_index.get(conn.this_hash.as_buf());

        for ptr in guards {
            if conn.solved_guards.contains(&ptr) {
                continue;
            }

            let hash = store.get_block_hash(ptr);

            trace!(store.logger, "Connect block - set-hash-loop";
                "guard" => format!("{:?}", ptr),
                "hash" => format!("{:?}",   hash),
                "conn"  => format!("{:?}",   conn));

            store.spent_tree.revolve_orphan_pointers(
                &mut store.transactions,
                &mut store.tx_index,
                ptr
            );

            store.spent_tree.connect_block(&mut store.spent_index, &store.logger, conn.block, ptr)?;

            todo.push(Connection {
                block: ptr,
                block_hash: hash,
                solved_guards: vec![]

            });

        }
    }

    Ok(())
}

/// Returns true if the block is already stored
fn block_exists(store: & mut Store, block_hash: Hash32) -> bool {
    let ptr = store.block_index.get(block_hash);

    ptr.iter().any( | ptr | !ptr.is_guard())

}

/// Verifies and stores the transactions in the block.
/// Also verifies the merkle_root & the amounts
///
/// Returns a list fileptrs to the transactions
///
fn verify_and_store_transactions(store: &mut Store, block: &Block) -> BlockResult<Vec<Record>> {

    let chunks: Vec<_> = block.txs.par_chunks(PARALLEL_HASHING_THRESHOLD).map(|chunk_tx| {

        let len = chunk_tx.len();

        let mut hashes:  Vec<Hash32Buf> = Vec::with_capacity(len); // accurate
        let mut records: Vec<Record>    = Vec::with_capacity(len * 3); // estimate (guessing 2 in per tx)

        let ref mut tx_index = &mut store.tx_index.clone();
        let ref mut tx_store = &mut store.transactions.clone();

        for tx in chunk_tx {

            let hash = Hash32Buf::double_sha256(tx.to_raw());
            hashes.push(hash);

            let res = tx.verify_and_store(tx_index, tx_store, store.initial_sync, hash.as_ref()).unwrap();

            // AlreadyExists and VerifiedAndStored are both ok here
            let ptr = match res {
                transaction::TransactionOk::AlreadyExists(ptr) => ptr,
                transaction::TransactionOk::VerifiedAndStored(ptr) => ptr
            };

            records.push(Record::new_transaction(ptr));
            for rec in tx.get_output_records(tx_index) {
                records.push(rec);
            }
        }
        (hashes,records)
    }).collect();

    // split
    let (hashes,records): (Vec<_>, Vec<_>) = chunks.into_iter().unzip();

    // flatten
    let hashes  = hashes.into_iter().flat_map(|x| x);
    let records = records.into_iter().flat_map(|x| x);

    // check merkle roots
    let calculated_merkle_root = merkle_tree::get_merkle_root(hashes.collect());
    block.verify_merkle_root(calculated_merkle_root.as_ref()).unwrap();

    Ok(records.collect())
}

/// Validates and stores a block;
///
pub fn add_block(store: &mut Store, buffer: &[u8]) {

    let block_logger = slog::Logger::new(&store.logger, o!());
    info!(block_logger, "add_block - start");

    // parse & hash block
    let block      = Block::new(buffer) .unwrap();
    let block_hash = Hash32Buf::double_sha256( block.header.to_raw());

    info!(block_logger, "add_block - hashed"; "hash" => format!("{:?}", block_hash));

    // already done?
    if block_exists(store, block_hash.as_ref()) {
        info!(store.logger, "add_block - Block already exists");
        return;
    }

    block.verify_block_size().unwrap();

    // check and store the transactions in block_content and check the merkle_root
    let spent_tree_ptrs = verify_and_store_transactions(store, &block).unwrap();

    // store the blockheader in block_content
    let block_header_ptr = store.block_headers.write( &block.header.to_raw());

    // we also store the txcount, although we only use it for a reindex benchmark
    let _ = store.block_headers.write_fixed( &block.txs.len());

    // store the block in the spent_tree

    let block_ptr       = store.spent_tree.store_block(block_header_ptr, spent_tree_ptrs);

    if is_genesis_block(block_hash.as_ref()) {

        info ! (block_logger, "add_block - storing genesis block");

        // there is None previous block, but we call connect_block anyway as this will also
        // connect to next blocks if they are already in
        connect_block(store, block_hash.as_ref(), None, block_ptr).unwrap();
    }
    else {

        // we retrieve the pointer to the end of the previous block from the hash-index
        // if it is not yet in, this hash will be inserted as a guard-block
        let previous_block = store.block_index.get_or_set( block.header.prev_hash, block_ptr.to_guard());

        info! (block_logger, "add_block - tranactions done";
            "previous" => format!("{:?}", block.header.prev_hash),
            "ptr" => format!("{:?}", previous_block));

        // if it is in, we will connect
        if let Some(previous_block) = previous_block {

            connect_block(store, block_hash.as_ref(), Some(previous_block), block_ptr).unwrap();
        }

    }

    // TODO verify amounts
    // TODO verify PoW
    // TODO verify header-syntax

    info!(block_logger, "add_block - done");
}

#[cfg(test)]
mod tests {

    use store;
    use super::*;

    #[test]
    fn test_clone_into_thread() {

        struct X { data: Vec<u32> };
        impl Clone for X {
            fn clone(&self) -> X { X { data: self.data.clone() } }
        }
        let x = X { data: vec![1,2,3,4,5,6,7,8,9,10]};

        let y = vec![10,11,12,13,14,15,16,17,18,19,20];

        y.into_par_iter().map(|z| {
            let u = &mut x.clone(); // is this possible?
            println!("{:?} {:?} ", z, u.data); u.data.push(2);
        });
    }

    #[test]
    fn test_block_simple() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();

        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        add_block(&mut store, &block0);
        add_block(&mut store, &block1);
        add_block(&mut store, &block2);

    }

    #[test]
    fn test_blocks_reorder() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();
        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        //        add_block(&mut store, &block0);

        println!("block1 = {:?}", block1);
        //println!("tx1 = {:?}", ::hash::Hash32Buf::double_sha256(&tx1));
        add_block(&mut store, &block0);
        add_block(&mut store, &block2);
        add_block(&mut store, &block1);

    }

}

<commit_msg>More metrics for transaction processing<commit_after>/// Implements the block_add procedure

/*

Block storing is a tricky part; blocks are stored in the spent-tree and referenced in the
 hash-index

 This can go out of order:  For instance consider 5 blocks added in the order A, B, D, E, C
 (for this pseudocode, each block has the previous letter as prev_block_hash)

 We show the some pseudocode for actions on hashindex (hi) and spent-tree (st),
 for the insertion of this sequence

 insert A:
    st.store_block(A)
    fn do_connect(null,A) =
      (prev = null, no get_or_set)
      hi.set(A)

 insert B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
      hi.set(B)

 insert D:
    st.store_block(D)
    hi.get_or_set(C, guard[D]) return none & adds guard[D] at hash C

 insert E:
   st.store_block(E)
   hi.get_or_set(D, guard[E]) return none & adds guard[E] at hash D

 insert C:
   st.store_block(C)
   hi.get_or_set(B, guard[C]) returns B
   fn do_connect(B,C) =
      st.connect_block(B,C)
      hi.set(C) -> fail due to guard([D])

        loop {
            hi.get(C) -> return guard[D]
            do_connect(C,D)
            hi.set(C, guard([D]) -> fail or break
        }

  Now let us consider what happens when C' is inserted *during* processing of B. Copyied from B above:
  B:
    st.store_block(B)
    hi.get_or_set(A, guard[B]) returns A
    fn do_connect(A,B) =
      st.connect_block(A,B)
        < here C' is inserted as B -> guard[C']
      hi.set(B) -> fail due to guard[C']
      loop {
            hi.get(B) -> return guard[C']
            do_connect(B,C')
            hi.set(B, guard([C']) -> success!
        }

*/

use hash::*;
use util::*;
use buffer::*;
use rayon::prelude::*;
use slog ;

use store::Store;
use transaction;
use merkle_tree;
use block::*;
use store::Record;
use store::BlockPtr;
use store::HashIndexGuard;

type BlockResult<T> = Result<T, BlockError>;

// minimum number of hashes to use parallel hashing
const PARALLEL_HASHING_THRESHOLD: usize = 40;

/// Returns true if the given hash is the hash of a genesis block
fn is_genesis_block(hash: Hash32) -> bool {
    const HASH_GENESIS: &'static str =
        "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";

    let genesis = Hash32Buf::from_slice(&from_hex_rev(HASH_GENESIS));

    genesis.as_ref() == hash
}

// Connects two blocks (A,B) in the spent-tree and then stores the hash of B in the hash-index
// Connecting the blocks will verify double-spents
//
// It can be that another block C is also waiting for B; this will trigger their connection (B,C) too
// and maybe (C,D)... etcetera
//
// This would be neat to do recursively, but this could exhaust the stack , we use a loop with
// a to_do for connections.
fn connect_block(
    store:           &mut Store,
    this_block_hash: Hash32,
    previous_block:  Option<BlockPtr>,
    this_block:      BlockPtr)

    -> BlockResult<()>
{
    trace!(store.logger, "Connect block";
        "this_hash"  =>  format!("{:?}", this_block_hash),
        "prev_end"   =>  format!("{:?}", previous_block),
        "this_start" =>  format!("{:?}", this_block)
    );

    // we lay connections between the end of one block and the start of this_block
    // prev_end is None only for genesis
    #[derive(Debug)]
    struct Connection {
        block:         BlockPtr,
        block_hash:    Hash32Buf,
        solved_guards: Vec<BlockPtr>
    }

    // connect first block ...
    if let Some(previous_block) = previous_block {
        store.spent_tree.connect_block( &mut store.spent_index, & store.logger, previous_block, this_block) ?;
    }

    // The to_do list contains blocks that are connected to their previous but not yet added to the
    // block-index.
    let mut todo = vec![Connection {
        block:         this_block,
        block_hash:    this_block_hash.as_buf(),
        solved_guards: vec![]
    }];

    while let Some(conn) = todo.pop() {

        trace!(store.logger, "Connect block - set-hash-loop";
            "conn"  => format!("{:?}",   conn));

        // if we can store this hash we can move to the next one
        if store.block_index.set(conn.block_hash.as_ref(), conn.block.to_non_guard(), &conn.solved_guards, false) {
            trace!(store.logger, "Connect block - set-hash-loop - ok");
            continue;
        }

        let guards = store.block_index.get(conn.block_hash.as_ref());

        if guards.iter().any(|ptr| !ptr.is_guard()) {
            // this is not a guard, this is _this_ block. It seems the block
            // was added by a concurrent user; will do fine.
            trace!(store.logger, "Connect block - set-hash-loop - concurrent add");
            continue;
        }

        //let guards = store.hash_index.get(conn.this_hash);
        todo.push(Connection {
            block: conn.block,
            block_hash: conn.block_hash,
            solved_guards: guards.clone()
        });

        //let guards = store.hash_index.get(conn.this_hash.as_buf());

        for ptr in guards {
            if conn.solved_guards.contains(&ptr) {
                continue;
            }

            let hash = store.get_block_hash(ptr);

            trace!(store.logger, "Connect block - set-hash-loop";
                "guard" => format!("{:?}", ptr),
                "hash" => format!("{:?}",   hash),
                "conn"  => format!("{:?}",   conn));

            store.spent_tree.revolve_orphan_pointers(
                &mut store.transactions,
                &mut store.tx_index,
                ptr
            );

            store.spent_tree.connect_block(&mut store.spent_index, &store.logger, conn.block, ptr)?;

            todo.push(Connection {
                block: ptr,
                block_hash: hash,
                solved_guards: vec![]

            });

        }
    }

    Ok(())
}

/// Returns true if the block is already stored
fn block_exists(store: & mut Store, block_hash: Hash32) -> bool {
    let ptr = store.block_index.get(block_hash);

    ptr.iter().any( | ptr | !ptr.is_guard())

}

/// Verifies and stores the transactions in the block.
/// Also verifies the merkle_root & the amounts
///
/// Returns a list fileptrs to the transactions
///
fn verify_and_store_transactions(store: &mut Store, block: &Block) -> BlockResult<Vec<Record>> {

    let timer = ::std::time::Instant::now();

    let chunks: Vec<_> = block.txs.par_chunks(PARALLEL_HASHING_THRESHOLD).map(|chunk_tx| {

        let len = chunk_tx.len();

        let mut hashes:  Vec<Hash32Buf> = Vec::with_capacity(len); // accurate
        let mut records: Vec<Record>    = Vec::with_capacity(len * 3); // estimate (guessing 2 in per tx)

        let ref mut tx_index = &mut store.tx_index.clone();
        let ref mut tx_store = &mut store.transactions.clone();

        for tx in chunk_tx {

            let hash = Hash32Buf::double_sha256(tx.to_raw());
            hashes.push(hash);

            let res = tx.verify_and_store(tx_index, tx_store, store.initial_sync, hash.as_ref()).unwrap();

            // AlreadyExists and VerifiedAndStored are both ok here
            let ptr = match res {
                transaction::TransactionOk::AlreadyExists(ptr) => ptr,
                transaction::TransactionOk::VerifiedAndStored(ptr) => ptr
            };

            records.push(Record::new_transaction(ptr));
            for rec in tx.get_output_records(tx_index) {
                records.push(rec);
            }
        }
        (hashes,records)
    }).collect();

    // split
    let (hashes,records): (Vec<_>, Vec<_>) = chunks.into_iter().unzip();

    // flatten
    let hashes:  Vec<Hash32Buf> = hashes.into_iter().flat_map(|x| x).collect();
    let records: Vec<Record>    = records.into_iter().flat_map(|x| x).collect();
    let rec_count: usize = records.len();
    let tx_count: usize  = hashes.len();

    // check merkle roots
    let calculated_merkle_root = merkle_tree::get_merkle_root(hashes);
    block.verify_merkle_root(calculated_merkle_root.as_ref()).unwrap();

    let elapsed : usize = timer.elapsed().as_secs() as usize * 1000 +
        timer.elapsed().subsec_nanos() as usize / 1_000_000 as usize;

    if rec_count > 0 && rec_count-tx_count > 0 {
        info!(store.logger, "add_block - transactions done";
            "input_avg_ms" => elapsed / (rec_count - tx_count),
            "tx_avg_ms" => elapsed / tx_count);
    }
    Ok(records)
}

/// Validates and stores a block;
///
pub fn add_block(store: &mut Store, buffer: &[u8]) {

    let block_logger = slog::Logger::new(&store.logger, o!());
    info!(block_logger, "add_block - start");

    // parse & hash block
    let block      = Block::new(buffer) .unwrap();
    let block_hash = Hash32Buf::double_sha256( block.header.to_raw());

    info!(block_logger, "add_block - hashed"; "hash" => format!("{:?}", block_hash));

    // already done?
    if block_exists(store, block_hash.as_ref()) {
        info!(store.logger, "add_block - Block already exists");
        return;
    }

    block.verify_block_size().unwrap();

    // check and store the transactions in block_content and check the merkle_root
    let spent_tree_ptrs = verify_and_store_transactions(store, &block).unwrap();

    // store the blockheader in block_content
    let block_header_ptr = store.block_headers.write( &block.header.to_raw());

    // we also store the txcount, although we only use it for a reindex benchmark
    let _ = store.block_headers.write_fixed( &block.txs.len());

    // store the block in the spent_tree

    let block_ptr       = store.spent_tree.store_block(block_header_ptr, spent_tree_ptrs);

    if is_genesis_block(block_hash.as_ref()) {

        info ! (block_logger, "add_block - storing genesis block");

        // there is None previous block, but we call connect_block anyway as this will also
        // connect to next blocks if they are already in
        connect_block(store, block_hash.as_ref(), None, block_ptr).unwrap();
    }
    else {

        // we retrieve the pointer to the end of the previous block from the hash-index
        // if it is not yet in, this hash will be inserted as a guard-block
        let previous_block = store.block_index.get_or_set( block.header.prev_hash, block_ptr.to_guard());

        info! (block_logger, "add_block - block-index done";
            "previous" => format!("{:?}", block.header.prev_hash),
            "ptr" => format!("{:?}", previous_block));

        // if it is in, we will connect
        if let Some(previous_block) = previous_block {

            connect_block(store, block_hash.as_ref(), Some(previous_block), block_ptr).unwrap();
        }

    }

    // TODO verify amounts
    // TODO verify PoW
    // TODO verify header-syntax

    info!(block_logger, "add_block - done");
}

#[cfg(test)]
mod tests {

    use store;
    use super::*;

    #[test]
    fn test_clone_into_thread() {

        struct X { data: Vec<u32> };
        impl Clone for X {
            fn clone(&self) -> X { X { data: self.data.clone() } }
        }
        let x = X { data: vec![1,2,3,4,5,6,7,8,9,10]};

        let y = vec![10,11,12,13,14,15,16,17,18,19,20];

        y.into_par_iter().map(|z| {
            let u = &mut x.clone(); // is this possible?
            println!("{:?} {:?} ", z, u.data); u.data.push(2);
        });
    }

    #[test]
    fn test_block_simple() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();

        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        add_block(&mut store, &block0);
        add_block(&mut store, &block1);
        add_block(&mut store, &block2);

    }

    #[test]
    fn test_blocks_reorder() {

        let mut store = store::Store::new(& test_cfg!());

        tx_builder!(bld);

        let block0 = genesis!();
        let block1 = blk!(prev = block0;
            tx!(bld; coinbase => b;11 ),
            tx!(bld; b => c,e )
        );

        let block2 = blk!(prev = block1;
            tx!(bld; coinbase => f;12 ),
            tx!(bld; c => g )
        );

        //        add_block(&mut store, &block0);

        println!("block1 = {:?}", block1);
        //println!("tx1 = {:?}", ::hash::Hash32Buf::double_sha256(&tx1));
        add_block(&mut store, &block0);
        add_block(&mut store, &block2);
        add_block(&mut store, &block1);

    }

}

<|endoftext|>