<commit_before>extern crate redis;

use redis::{Client, Commands, Connection, RedisResult};
use std::collections::HashSet;

type UserId = u64;

fn add_friend(conn: &Connection, my_id: UserId, their_id: UserId) -> RedisResult<()> {
    let my_key = format!("friends:{}", my_id);
    let their_key = format!("friends:{}", their_id);
    let _: () = try!(conn.sadd(my_key, their_id));
    let _: () = try!(conn.sadd(their_key, my_id));
    Ok(())
}

fn friends_in_common(conn: &Connection, my_id: UserId, their_id: UserId) -> RedisResult<HashSet<UserId>> {
    let my_key = format!("friends:{}", my_id);
    let their_key = format!("friends:{}", their_id);
    let result: HashSet<UserId> = try!(conn.sinter((my_key, their_key)));
    Ok(result)
}

fn main() {
    println!("24 days of Rust - redis (day 18)");
    let client = Client::open("redis://127.0.0.1/").unwrap();
    let conn = client.get_connection().unwrap();
    let _: () = conn.set("answer", 42i).unwrap();
    let answer: int = conn.get("answer").unwrap();
    println!("Answer: {}", answer);

    for i in range(1, 10u64) {
        add_friend(&conn, i, i + 2).ok().expect("Friendship failed :(");
    }
    println!("{}", friends_in_common(&conn, 2, 3));
}
<commit_msg>Leaderboard example.<commit_after>extern crate redis;

use redis::{Client, Commands, Connection, RedisResult};
use std::collections::HashSet;
use std::rand;

type UserId = u64;

fn add_friend(conn: &Connection, my_id: UserId, their_id: UserId) -> RedisResult<()> {
    let my_key = format!("friends:{}", my_id);
    let their_key = format!("friends:{}", their_id);
    let _: () = try!(conn.sadd(my_key, their_id));
    let _: () = try!(conn.sadd(their_key, my_id));
    Ok(())
}

fn friends_in_common(conn: &Connection, my_id: UserId, their_id: UserId) -> RedisResult<HashSet<UserId>> {
    let my_key = format!("friends:{}", my_id);
    let their_key = format!("friends:{}", their_id);
    Ok(try!(conn.sinter((my_key, their_key))))
}

fn add_score(conn: &Connection, username: &str, score: uint) -> RedisResult<()> {
    conn.zadd("leaderboard", username, score)
}

type Leaderboard = Vec<(String, uint)>;

fn show_leaderboard(conn: &Connection, n: int) {
    let result: RedisResult<Leaderboard> = conn.zrevrange_withscores("leaderboard", 0, n - 1);
    match result {
        Ok(board) => {
            println!("----==== Top {} players ====----", n);
            for (i, (username, score)) in board.into_iter().enumerate() {
                println!("{:<5} {:^20} {:>4}", i + 1, username, score);
            }
        },
        Err(_) => println!("Failed to fetch leaderboard."),
    }
}

fn main() {
    println!("24 days of Rust - redis (day 18)");
    let client = Client::open("redis://127.0.0.1/").unwrap();
    let conn = client.get_connection().unwrap();
    let _: () = conn.set("answer", 42i).unwrap();
    let answer: int = conn.get("answer").unwrap();
    println!("Answer: {}", answer);

    for i in range(1, 10u64) {
        add_friend(&conn, i, i + 2).ok().expect("Friendship failed :(");
    }
    println!("You have {} friends in common.",
             friends_in_common(&conn, 2, 3).map(|s| s.len()).unwrap_or(0));

    let players = vec!["raynor", "kerrigan", "mengsk", "zasz", "tassadar"];
    for player in players.iter() {
        let score = rand::random::<uint>() % 1000;
        add_score(&conn, *player, score).ok().expect("Nuclear launch detected");
    }
    show_leaderboard(&conn, 3);
}
<|endoftext|>


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

use registry::Registry;
use std::io;

#[allow(missing_copy_implementations)]
pub struct DebugStructGenerator;

impl super::Generator for DebugStructGenerator {
    fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
        try!(write_header(dest));
        try!(write_type_aliases(registry, dest));
        try!(write_enums(registry, dest));
        try!(write_fnptr_struct_def(dest));
        try!(write_panicking_fns(registry, dest));
        try!(write_struct(registry, dest));
        try!(write_impl(registry, dest));
        Ok(())
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the
///  bindings.
fn write_header<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        mod __gl_imports {{
            pub use std::mem;
            pub use std::marker::Send;
            pub use std::os::raw;
        }}
    "#)
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_types`.
fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        pub mod types {{
            #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)]
    "#));

    try!(super::gen_types(registry.api, dest));

    writeln!(dest, "}}")
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for enm in &registry.enums {
        try!(super::gen_enum_item(enm, "types::", dest));
    }

    Ok(())
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, "
        #[allow(dead_code, missing_copy_implementations, raw_pointer_derive)]
        #[derive(Clone)]
        pub struct FnPtr {{
            /// The function pointer that will be used when calling the function.
            f: *const __gl_imports::raw::c_void,
            /// True if the pointer points to a real function, false if points to a `panic!` fn.
            is_loaded: bool,
        }}

        impl FnPtr {{
            /// Creates a `FnPtr` from a load attempt.
            fn new(ptr: *const __gl_imports::raw::c_void) -> FnPtr {{
                if ptr.is_null() {{
                    FnPtr {{
                        f: missing_fn_panic as *const __gl_imports::raw::c_void,
                        is_loaded: false
                    }}
                }} else {{
                    FnPtr {{ f: ptr, is_loaded: true }}
                }}
            }}

            /// Returns `true` if the function has been successfully loaded.
            ///
            /// If it returns `false`, calling the corresponding function will fail.
            #[inline]
            #[allow(dead_code)]
            pub fn is_loaded(&self) -> bool {{
                self.is_loaded
            }}
        }}
    ")
}

/// Creates a `panicking` module which contains one function per GL command.
///
/// These functions are the mocks that are called if the real function could not be loaded.
fn write_panicking_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest,
        "#[inline(never)]
        fn missing_fn_panic() -> ! {{
            panic!(\"{api} function was not loaded\")
        }}",
        api = registry.api
    )
}

/// Creates a structure which stores all the `FnPtr` of the bindings.
///
/// The name of the struct corresponds to the namespace.
fn write_struct<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, "
        #[allow(non_camel_case_types, non_snake_case, dead_code)]
        #[derive(Clone)]
        pub struct {api} {{",
        api = super::gen_struct_name(registry.api)
    ));

    for cmd in &registry.cmds {
        if let Some(v) = registry.aliases.get(&cmd.proto.ident) {
            try!(writeln!(dest, "/// Fallbacks: {}", v.join(", ")));
        }
        try!(writeln!(dest, "pub {name}: FnPtr,", name = cmd.proto.ident));
    }

    writeln!(dest, "}}")
}

/// Creates the `impl` of the structure created by `write_struct`.
fn write_impl<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest,
        "impl {api} {{
            /// Load each OpenGL symbol using a custom load function. This allows for the
            /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
            ///
            /// ~~~ignore
            /// let gl = Gl::load_with(|s| glfw.get_proc_address(s));
            /// ~~~
            #[allow(dead_code, unused_variables)]
            pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&str) -> *const __gl_imports::raw::c_void {{
                let mut metaloadfn = |symbol: &str, symbols: &[&str]| {{
                    let mut ptr = loadfn(symbol);
                    if ptr.is_null() {{
                        for &sym in symbols {{
                            ptr = loadfn(sym);
                            if !ptr.is_null() {{ break; }}
                        }}
                    }}
                    ptr
                }};
                {api} {{",
        api = super::gen_struct_name(registry.api)
    ));

    for cmd in &registry.cmds {
        try!(writeln!(dest,
            "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),",
            name = cmd.proto.ident,
            symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident),
            fallbacks = match registry.aliases.get(&cmd.proto.ident) {
                Some(fbs) => {
                    fbs.iter()
                       .map(|name| format!("\"{}\"", super::gen_symbol_name(registry.api, &name)))
                       .collect::<Vec<_>>().join(", ")
                },
                None => format!(""),
            },
        ))
    }

    try!(writeln!(dest,
            "}}
        }}"
    ));

    for cmd in &registry.cmds {
        let idents = super::gen_parameters(cmd, true, false);
        let typed_params = super::gen_parameters(cmd, false, true);
        let println = format!("println!(\"[OpenGL] {}({})\" {});",
                                cmd.proto.ident,
                                (0 .. idents.len()).map(|_| "{:?}".to_string()).collect::<Vec<_>>().join(", "),
                                idents.iter().zip(typed_params.iter())
                                      .map(|(name, ty)| {
                                          if ty.contains("GLDEBUGPROC") {
                                              format!(", \"<callback>\"")
                                          } else {
                                              format!(", {}", name)
                                          }
                                      }).collect::<Vec<_>>().concat());

        try!(writeln!(dest,
            "#[allow(non_snake_case, unused_variables, dead_code)]
            #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \
                {println}
                let r = __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\
                    (self.{name}.f)({idents});
                {print_err}
                r
            }}",
            name = cmd.proto.ident,
            params = super::gen_parameters(cmd, true, true).join(", "),
            typed_params = typed_params.join(", "),
            return_suffix = cmd.proto.ty,
            idents = idents.join(", "),
            println = println,
            print_err = if cmd.proto.ident != "GetError" && registry.cmds.iter().find(|cmd| cmd.proto.ident == "GetError").is_some() {
                format!(r#"match __gl_imports::mem::transmute::<_, extern "system" fn() -> u32>
                    (self.GetError.f)() {{ 0 => (), r => println!("[OpenGL] ^ GL error triggered: {{}}", r) }}"#)
            } else {
                format!("")
            }
        ))
    }

    writeln!(dest,
        "}}

        unsafe impl __gl_imports::Send for {api} {{}}",
        api = super::gen_struct_name(registry.api)
    )
}
<commit_msg>Remove allow raw_pointer_derive<commit_after>// Copyright 2015 Brendan Zabarauskas and the gl-rs developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use registry::Registry;
use std::io;

#[allow(missing_copy_implementations)]
pub struct DebugStructGenerator;

impl super::Generator for DebugStructGenerator {
    fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
        try!(write_header(dest));
        try!(write_type_aliases(registry, dest));
        try!(write_enums(registry, dest));
        try!(write_fnptr_struct_def(dest));
        try!(write_panicking_fns(registry, dest));
        try!(write_struct(registry, dest));
        try!(write_impl(registry, dest));
        Ok(())
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the
///  bindings.
fn write_header<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        mod __gl_imports {{
            pub use std::mem;
            pub use std::marker::Send;
            pub use std::os::raw;
        }}
    "#)
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_types`.
fn write_type_aliases<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        pub mod types {{
            #![allow(non_camel_case_types, non_snake_case, dead_code, missing_copy_implementations)]
    "#));

    try!(super::gen_types(registry.api, dest));

    writeln!(dest, "}}")
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for enm in &registry.enums {
        try!(super::gen_enum_item(enm, "types::", dest));
    }

    Ok(())
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, "
        #[allow(dead_code, missing_copy_implementations)]
        #[derive(Clone)]
        pub struct FnPtr {{
            /// The function pointer that will be used when calling the function.
            f: *const __gl_imports::raw::c_void,
            /// True if the pointer points to a real function, false if points to a `panic!` fn.
            is_loaded: bool,
        }}

        impl FnPtr {{
            /// Creates a `FnPtr` from a load attempt.
            fn new(ptr: *const __gl_imports::raw::c_void) -> FnPtr {{
                if ptr.is_null() {{
                    FnPtr {{
                        f: missing_fn_panic as *const __gl_imports::raw::c_void,
                        is_loaded: false
                    }}
                }} else {{
                    FnPtr {{ f: ptr, is_loaded: true }}
                }}
            }}

            /// Returns `true` if the function has been successfully loaded.
            ///
            /// If it returns `false`, calling the corresponding function will fail.
            #[inline]
            #[allow(dead_code)]
            pub fn is_loaded(&self) -> bool {{
                self.is_loaded
            }}
        }}
    ")
}

/// Creates a `panicking` module which contains one function per GL command.
///
/// These functions are the mocks that are called if the real function could not be loaded.
fn write_panicking_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest,
        "#[inline(never)]
        fn missing_fn_panic() -> ! {{
            panic!(\"{api} function was not loaded\")
        }}",
        api = registry.api
    )
}

/// Creates a structure which stores all the `FnPtr` of the bindings.
///
/// The name of the struct corresponds to the namespace.
fn write_struct<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, "
        #[allow(non_camel_case_types, non_snake_case, dead_code)]
        #[derive(Clone)]
        pub struct {api} {{",
        api = super::gen_struct_name(registry.api)
    ));

    for cmd in &registry.cmds {
        if let Some(v) = registry.aliases.get(&cmd.proto.ident) {
            try!(writeln!(dest, "/// Fallbacks: {}", v.join(", ")));
        }
        try!(writeln!(dest, "pub {name}: FnPtr,", name = cmd.proto.ident));
    }

    writeln!(dest, "}}")
}

/// Creates the `impl` of the structure created by `write_struct`.
fn write_impl<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest,
        "impl {api} {{
            /// Load each OpenGL symbol using a custom load function. This allows for the
            /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
            ///
            /// ~~~ignore
            /// let gl = Gl::load_with(|s| glfw.get_proc_address(s));
            /// ~~~
            #[allow(dead_code, unused_variables)]
            pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&str) -> *const __gl_imports::raw::c_void {{
                let mut metaloadfn = |symbol: &str, symbols: &[&str]| {{
                    let mut ptr = loadfn(symbol);
                    if ptr.is_null() {{
                        for &sym in symbols {{
                            ptr = loadfn(sym);
                            if !ptr.is_null() {{ break; }}
                        }}
                    }}
                    ptr
                }};
                {api} {{",
        api = super::gen_struct_name(registry.api)
    ));

    for cmd in &registry.cmds {
        try!(writeln!(dest,
            "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),",
            name = cmd.proto.ident,
            symbol = super::gen_symbol_name(registry.api, &cmd.proto.ident),
            fallbacks = match registry.aliases.get(&cmd.proto.ident) {
                Some(fbs) => {
                    fbs.iter()
                       .map(|name| format!("\"{}\"", super::gen_symbol_name(registry.api, &name)))
                       .collect::<Vec<_>>().join(", ")
                },
                None => format!(""),
            },
        ))
    }

    try!(writeln!(dest,
            "}}
        }}"
    ));

    for cmd in &registry.cmds {
        let idents = super::gen_parameters(cmd, true, false);
        let typed_params = super::gen_parameters(cmd, false, true);
        let println = format!("println!(\"[OpenGL] {}({})\" {});",
                                cmd.proto.ident,
                                (0 .. idents.len()).map(|_| "{:?}".to_string()).collect::<Vec<_>>().join(", "),
                                idents.iter().zip(typed_params.iter())
                                      .map(|(name, ty)| {
                                          if ty.contains("GLDEBUGPROC") {
                                              format!(", \"<callback>\"")
                                          } else {
                                              format!(", {}", name)
                                          }
                                      }).collect::<Vec<_>>().concat());

        try!(writeln!(dest,
            "#[allow(non_snake_case, unused_variables, dead_code)]
            #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \
                {println}
                let r = __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\
                    (self.{name}.f)({idents});
                {print_err}
                r
            }}",
            name = cmd.proto.ident,
            params = super::gen_parameters(cmd, true, true).join(", "),
            typed_params = typed_params.join(", "),
            return_suffix = cmd.proto.ty,
            idents = idents.join(", "),
            println = println,
            print_err = if cmd.proto.ident != "GetError" && registry.cmds.iter().find(|cmd| cmd.proto.ident == "GetError").is_some() {
                format!(r#"match __gl_imports::mem::transmute::<_, extern "system" fn() -> u32>
                    (self.GetError.f)() {{ 0 => (), r => println!("[OpenGL] ^ GL error triggered: {{}}", r) }}"#)
            } else {
                format!("")
            }
        ))
    }

    writeln!(dest,
        "}}

        unsafe impl __gl_imports::Send for {api} {{}}",
        api = super::gen_struct_name(registry.api)
    )
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::string::FromUtf8Error;
use hyper;
use serde_json;
use time;
use url;

#[derive(Debug, Deserialize)]
pub struct Neo4jError {
    pub message: String,
    pub code: String,
}

#[derive(Debug)]
pub struct GraphError {
    neo4j_errors: Option<Vec<Neo4jError>>,
    cause: Option<Box<Error>>,
}

impl GraphError {
    pub fn new_neo4j_error(errors: Vec<Neo4jError>) -> Self {
        GraphError {
            neo4j_errors: Some(errors),
            cause: None,
        }
    }

    pub fn new_error(error: Box<Error>) -> Self {
        GraphError {
            neo4j_errors: None,
            cause: Some(error),
        }
    }
}

impl fmt::Display for GraphError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl Error for GraphError {
    fn description(&self) -> &str {
        match self.cause {
            Some(ref cause) => cause.description(),
            None => "Neo4j Error"
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.cause {
            None => None,
            Some(ref e) => Some(&**e)
        }
    }
}

#[derive(Debug)]
pub struct TransactionError(pub String);

impl fmt::Display for TransactionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for TransactionError {
    fn description(&self) -> &str {
        &self.0
    }
}

impl From<TransactionError> for GraphError {
    fn from(error: TransactionError) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<FromUtf8Error> for GraphError {
    fn from(error: FromUtf8Error) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<url::ParseError> for GraphError {
    fn from(error: url::ParseError) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<hyper::error::Error> for GraphError {
    fn from(error: hyper::error::Error) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<serde_json::error::Error> for GraphError {
    fn from(error: serde_json::error::Error) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

#[derive(Debug)]
pub struct TimeParseError(time::ParseError, String);

impl fmt::Display for TimeParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for TimeParseError {
    fn description(&self) -> &str {
        &self.1
    }
}

impl From<time::ParseError> for GraphError {
    fn from(error: time::ParseError) -> Self {
        GraphError::new_error(Box::new(TimeParseError(error, format!("{}", error))))
    }
}
<commit_msg>removed TransactionError<commit_after>use std::error::Error;
use std::fmt;
use std::string::FromUtf8Error;
use hyper;
use serde_json;
use time;
use url;

#[derive(Debug, Deserialize)]
pub struct Neo4jError {
    pub message: String,
    pub code: String,
}

#[derive(Debug)]
pub struct GraphError {
    neo4j_errors: Option<Vec<Neo4jError>>,
    cause: Option<Box<Error>>,
}

impl GraphError {
    pub fn new_neo4j_error(errors: Vec<Neo4jError>) -> Self {
        GraphError {
            neo4j_errors: Some(errors),
            cause: None,
        }
    }

    pub fn new_error(error: Box<Error>) -> Self {
        GraphError {
            neo4j_errors: None,
            cause: Some(error),
        }
    }
}

impl fmt::Display for GraphError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl Error for GraphError {
    fn description(&self) -> &str {
        match self.cause {
            Some(ref cause) => cause.description(),
            None => "Neo4j Error"
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.cause {
            None => None,
            Some(ref e) => Some(&**e)
        }
    }
}

impl From<FromUtf8Error> for GraphError {
    fn from(error: FromUtf8Error) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<url::ParseError> for GraphError {
    fn from(error: url::ParseError) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<hyper::error::Error> for GraphError {
    fn from(error: hyper::error::Error) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

impl From<serde_json::error::Error> for GraphError {
    fn from(error: serde_json::error::Error) -> Self {
        GraphError::new_error(Box::new(error))
    }
}

#[derive(Debug)]
pub struct TimeParseError(time::ParseError, String);

impl fmt::Display for TimeParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for TimeParseError {
    fn description(&self) -> &str {
        &self.1
    }
}

impl From<time::ParseError> for GraphError {
    fn from(error: time::ParseError) -> Self {
        GraphError::new_error(Box::new(TimeParseError(error, format!("{}", error))))
    }
}
<|endoftext|>


<commit_before>// Copyright © 2015 by Michael Dilger (of New Zealand)
// This code is licensed under the MIT license (see LICENSE-MIT for details)

use std::borrow::Cow;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;
use std::string::FromUtf8Error;

use super::{httparse, hyper, mime_multipart};

/// An error type for the `formdata` crate.
#[derive(Debug)]
pub enum Error {
    /// The Hyper request did not have a Content-Type header.
    NoRequestContentType,
    /// The Hyper request Content-Type top-level Mime was not `Multipart`.
    NotMultipart,
    /// The Hyper request Content-Type sub-level Mime was not `FormData`.
    NotFormData,
    /// The Content-Type header failed to specify boundary token.
    BoundaryNotSpecified,
    /// A multipart section contained only partial headers.
    PartialHeaders,
    /// A multipart section did not have the required Content-Disposition header.
    MissingDisposition,
    /// A multipart section did not have a valid corresponding Content-Disposition.
    InvalidDisposition,
    /// A multipart section Content-Disposition header failed to specify a name.
    NoName,
    /// The request body ended prior to reaching the expected terminating boundary.
    Eof,
    /// An HTTP parsing error from a multipart section.
    Httparse(httparse::Error),
    /// An I/O error.
    Io(io::Error),
    /// An error was returned from Hyper.
    Hyper(hyper::Error),
    /// An error occurred during UTF-8 processing.
    Utf8(FromUtf8Error),
    /// An error occurred during character decoding
    Decoding(Cow<'static, str>),
    /// A MIME multipart error
    Multipart(mime_multipart::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        Error::Httparse(err)
    }
}

impl From<hyper::Error> for Error {
    fn from(err: hyper::Error) -> Error {
        Error::Hyper(err)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::Utf8(err)
    }
}

impl From<mime_multipart::Error> for Error {
    fn from(err: mime_multipart::Error) -> Error {
        Error::Multipart(err)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Httparse(ref e) =>
                format!("{}: {:?}", self.description(), e).fmt(f),
            Error::Io(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Hyper(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Utf8(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Decoding(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Multipart(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            _ => format!("{}", self.description()).fmt(f),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str{
        match *self {
            Error::NoRequestContentType => "The Hyper request did not have a Content-Type header.",
            Error::NotMultipart =>
                "The Hyper request Content-Type top-level Mime was not multipart.",
            Error::NotFormData =>
                "The Hyper request Content-Type sub-level Mime was not form-data.",
            Error::BoundaryNotSpecified =>
                "The Content-Type header failed to specify a boundary token.",
            Error::PartialHeaders => "A multipart section contained only partial headers.",
            Error::MissingDisposition =>
                "A multipart section did not have the required Content-Disposition header.",
            Error::InvalidDisposition =>
                "A multipart section did not have a valid corresponding Content-Disposition.",
            Error::NoName =>
                "A multipart section Content-Disposition header failed to specify a name.",
            Error::Eof =>
                "The request body ended prior to reaching the expected terminating boundary.",
            Error::Httparse(_) =>
                "A parse error occurred while parsing the headers of a multipart section.",
            Error::Io(_) => "An I/O error occurred.",
            Error::Hyper(_) => "A Hyper error occurred.",
            Error::Utf8(_) => "A UTF-8 error occurred.",
            Error::Decoding(_) => "A decoding error occurred.",
            Error::Multipart(_) => "A MIME multipart decoding error occurred.",
        }
    }
}
<commit_msg>Implement Debug for Error manually so that the cause can be printed as well.<commit_after>// Copyright © 2015 by Michael Dilger (of New Zealand)
// This code is licensed under the MIT license (see LICENSE-MIT for details)

use std::borrow::Cow;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;
use std::string::FromUtf8Error;

use super::{httparse, hyper, mime_multipart};

/// An error type for the `formdata` crate.
pub enum Error {
    /// The Hyper request did not have a Content-Type header.
    NoRequestContentType,
    /// The Hyper request Content-Type top-level Mime was not `Multipart`.
    NotMultipart,
    /// The Hyper request Content-Type sub-level Mime was not `FormData`.
    NotFormData,
    /// The Content-Type header failed to specify boundary token.
    BoundaryNotSpecified,
    /// A multipart section contained only partial headers.
    PartialHeaders,
    /// A multipart section did not have the required Content-Disposition header.
    MissingDisposition,
    /// A multipart section did not have a valid corresponding Content-Disposition.
    InvalidDisposition,
    /// A multipart section Content-Disposition header failed to specify a name.
    NoName,
    /// The request body ended prior to reaching the expected terminating boundary.
    Eof,
    /// An HTTP parsing error from a multipart section.
    Httparse(httparse::Error),
    /// An I/O error.
    Io(io::Error),
    /// An error was returned from Hyper.
    Hyper(hyper::Error),
    /// An error occurred during UTF-8 processing.
    Utf8(FromUtf8Error),
    /// An error occurred during character decoding
    Decoding(Cow<'static, str>),
    /// A MIME multipart error
    Multipart(mime_multipart::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        Error::Httparse(err)
    }
}

impl From<hyper::Error> for Error {
    fn from(err: hyper::Error) -> Error {
        Error::Hyper(err)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::Utf8(err)
    }
}

impl From<mime_multipart::Error> for Error {
    fn from(err: mime_multipart::Error) -> Error {
        Error::Multipart(err)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Httparse(ref e) =>
                format!("{}: {:?}", self.description(), e).fmt(f),
            Error::Io(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Hyper(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Utf8(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Decoding(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            Error::Multipart(ref e) =>
                format!("{}: {}", self.description(), e).fmt(f),
            _ => format!("{}", self.description()).fmt(f),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!( f.write_str(&*self.description()) );
        if self.cause().is_some() {
            try!( write!(f, ": {:?}", self.cause().unwrap()) ); // recurse
        }
        Ok(())
    }
}

impl StdError for Error {
    fn description(&self) -> &str{
        match *self {
            Error::NoRequestContentType => "The Hyper request did not have a Content-Type header.",
            Error::NotMultipart =>
                "The Hyper request Content-Type top-level Mime was not multipart.",
            Error::NotFormData =>
                "The Hyper request Content-Type sub-level Mime was not form-data.",
            Error::BoundaryNotSpecified =>
                "The Content-Type header failed to specify a boundary token.",
            Error::PartialHeaders => "A multipart section contained only partial headers.",
            Error::MissingDisposition =>
                "A multipart section did not have the required Content-Disposition header.",
            Error::InvalidDisposition =>
                "A multipart section did not have a valid corresponding Content-Disposition.",
            Error::NoName =>
                "A multipart section Content-Disposition header failed to specify a name.",
            Error::Eof =>
                "The request body ended prior to reaching the expected terminating boundary.",
            Error::Httparse(_) =>
                "A parse error occurred while parsing the headers of a multipart section.",
            Error::Io(_) => "An I/O error occurred.",
            Error::Hyper(_) => "A Hyper error occurred.",
            Error::Utf8(_) => "A UTF-8 error occurred.",
            Error::Decoding(_) => "A decoding error occurred.",
            Error::Multipart(_) => "A MIME multipart error occurred.",
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::fmt::{self, Debug, Formatter};
#[cfg(feature = "display")]
use std::fmt::Display;
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
pub struct Group<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> Group<'a, K, V, RandomState> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<'a, K, V, RandomState> {
        Default::default()
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<'a, K, V, S> {
    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<'a, K, V, S> {
        GroupBuilder {
            map: PhantomData,
            capacity: 0,
            signals: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let map = &mut self.map;
        self.active.as_mut().and_then(move |active| map.get_mut(active))
    }

    /// Sets the current active item in the group.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: K) -> Option<K> {
        if self.map.contains_key(&k) {
            if self.active.as_ref().map_or(false, |a| a != &k) {
                if let Some(ref mut f) = self.signals {
                    f(Some(&k))
                }
            }
            self.active = Some(k);
            None
        } else {
            Some(k)
        }
    }

    /// Unsets the current active item in the group.
    #[inline]
    pub fn unset(&mut self) {
        if self.active.is_some() {
            self.active = None;
            if let Some(ref mut f) = self.signals {
                f(None);
            }
        }
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        self.get_mut().and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Record<'a, R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_saved())
    }

    /// Calls the [`set_unsaved`] method on the active record.
    ///
    /// [`set_unsaved`]: record/struct.Record.html#method.set_unsaved
    #[inline]
    pub fn set_unsaved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_unsaved())
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> Option<bool> {
        self.get().map(|stack| stack.is_saved())
    }

    /// Calls the [`exec`] method on the active record.
    ///
    /// [`exec`]: record/struct.Record.html#method.exec
    #[inline]
    pub fn exec<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |record| record.exec(cmd))
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.undo())
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_undo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_redo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_redo_string())
    }
}

impl<'a, K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("map", &self.map)
            .field("active", &self.active)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<'a, K: Hash + Eq + Display, V: Display> Display for Group<'a, K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.map {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, "* {}:\n{}", key, item)?;
            } else {
                writeln!(f, "  {}:\n{}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<'a, K: Hash + Eq, V> Default for Group<'a, K, V, RandomState> {
    #[inline]
    fn default() -> Group<'a, K, V, RandomState> {
        Group {
            map: HashMap::new(),
            active: None,
            signals: None,
        }
    }
}

/// Builder for a group.
pub struct GroupBuilder<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: PhantomData<(K, V, S)>,
    capacity: usize,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> GroupBuilder<'a, K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<'a, K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> GroupBuilder<'a, K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<'a, K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::*;
    /// # let _: Group<u8, u8> =
    /// Group::builder()
    ///     .signals(|k| match k {
    ///         Some(k) => println!("The new active stack is {}.", k),
    ///         None => println!("No active stack."),
    ///     })
    ///     .build();
    /// ```
    #[inline]
    pub fn signals<F>(mut self, f: F) -> GroupBuilder<'a, K, V, S>
    where
        F: FnMut(Option<&K>) + Send + Sync + 'a
    {
        self.signals = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<'a, K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signals: self.signals,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("map", &self.map)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<commit_msg>Remove default type of hasher for GroupBuilder<commit_after>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::fmt::{self, Debug, Formatter};
#[cfg(feature = "display")]
use std::fmt::Display;
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
pub struct Group<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> Group<'a, K, V, RandomState> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<'a, K, V, RandomState> {
        Default::default()
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<'a, K, V, S> {
    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<'a, K, V, S> {
        GroupBuilder {
            map: PhantomData,
            capacity: 0,
            signals: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let map = &mut self.map;
        self.active.as_mut().and_then(move |active| map.get_mut(active))
    }

    /// Sets the current active item in the group.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: K) -> Option<K> {
        if self.map.contains_key(&k) {
            if self.active.as_ref().map_or(false, |a| a != &k) {
                if let Some(ref mut f) = self.signals {
                    f(Some(&k))
                }
            }
            self.active = Some(k);
            None
        } else {
            Some(k)
        }
    }

    /// Unsets the current active item in the group.
    #[inline]
    pub fn unset(&mut self) {
        if self.active.is_some() {
            self.active = None;
            if let Some(ref mut f) = self.signals {
                f(None);
            }
        }
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        self.get_mut().and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Record<'a, R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_saved())
    }

    /// Calls the [`set_unsaved`] method on the active record.
    ///
    /// [`set_unsaved`]: record/struct.Record.html#method.set_unsaved
    #[inline]
    pub fn set_unsaved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_unsaved())
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> Option<bool> {
        self.get().map(|stack| stack.is_saved())
    }

    /// Calls the [`exec`] method on the active record.
    ///
    /// [`exec`]: record/struct.Record.html#method.exec
    #[inline]
    pub fn exec<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |record| record.exec(cmd))
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.undo())
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_undo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    #[cfg(feature = "display")]
    pub fn to_redo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_redo_string())
    }
}

impl<'a, K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("map", &self.map)
            .field("active", &self.active)
            .finish()
    }
}

#[cfg(feature = "display")]
impl<'a, K: Hash + Eq + Display, V: Display> Display for Group<'a, K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.map {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, "* {}:\n{}", key, item)?;
            } else {
                writeln!(f, "  {}:\n{}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<'a, K: Hash + Eq, V> Default for Group<'a, K, V, RandomState> {
    #[inline]
    fn default() -> Group<'a, K, V, RandomState> {
        Group {
            map: HashMap::new(),
            active: None,
            signals: None,
        }
    }
}

/// Builder for a group.
pub struct GroupBuilder<'a, K: Hash + Eq, V, S: BuildHasher> {
    map: PhantomData<(K, V, S)>,
    capacity: usize,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> GroupBuilder<'a, K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<'a, K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> GroupBuilder<'a, K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<'a, K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::*;
    /// # let _: Group<u8, u8> =
    /// Group::builder()
    ///     .signals(|k| match k {
    ///         Some(k) => println!("The new active stack is {}.", k),
    ///         None => println!("No active stack."),
    ///     })
    ///     .build();
    /// ```
    #[inline]
    pub fn signals<F>(mut self, f: F) -> GroupBuilder<'a, K, V, S>
    where
        F: FnMut(Option<&K>) + Send + Sync + 'a
    {
        self.signals = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<'a, K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signals: self.signals,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("map", &self.map)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<|endoftext|>


<commit_before><commit_msg>Add RDWR max message limit<commit_after><|endoftext|>


<commit_before>#![cfg_attr(feature = "middleware", feature(specialization))]

extern crate env_logger;
#[macro_use]
extern crate log;

#[macro_use]
extern crate edge;

#[macro_use]
extern crate lazy_static;

use edge::{json, Edge, Router, Cookie, Request, Response, Result, Action, Status, stream};
use edge::header::AccessControlAllowOrigin;

use std::io::Write;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

use std::collections::BTreeMap;

struct MyApp {
    counter: Arc<AtomicUsize>
}

lazy_static! {
    static ref COUNTER: Arc<AtomicUsize> = Default::default();
}

impl Default for MyApp {
    fn default() -> MyApp {
        debug!("MyApp::default");
        MyApp {
            counter: COUNTER.clone()
        }
    }
}

impl MyApp {

    fn home(&mut self, _req: &Request, res: &mut Response) -> Result {
        res.content_type("text/html; charset=UTF-8").header(AccessControlAllowOrigin::Any);
        let html = "<title>home</title>
Hello, world!
".to_string();
        ok!(html)
    }

    fn hello(&mut self, req: &Request, _res: &mut Response) -> Result {
        let cnt = self.counter.fetch_add(1, Ordering::SeqCst);

        let first_name = req.param("first_name").unwrap_or("John");
        let last_name = req.param("last_name").unwrap_or("Doe");

        let mut data = BTreeMap::new();
        data.insert("first_name", json::to_value(first_name));
        data.insert("last_name", json::to_value(last_name));
        data.insert("counter", json::to_value(&cnt));
        data.insert("content", json::to_value(r#"## Contents
This is a list:

- item 1
- item 2

"#));
        ok!("hello", data)
    }

    fn counter(&mut self, req: &Request, res: &mut Response) -> Result {
        let mut cookies = req.cookies();
        let name = cookies.find(|cookie| cookie.name == "name")
            .map_or("nope", |cookie| &cookie.value);
        println!("name cookie: {}", name);

        let mut data = BTreeMap::new();
        data.insert("name", json::to_value(name));
        let cnt = self.counter.load(Ordering::Relaxed);
        data.insert("counter", json::to_value(&cnt));
        res.content_type("application/json");
        ok!(json::to_value(&data))
    }

    fn login(&mut self, req: &Request, res: &mut Response) -> Result {
        let form = try!(req.form().map_err(|e| (Status::BadRequest, e.to_string())));
        if let Some(username) = form.get("username") {
            if username == "error with message" {
                try!(Err((Status::BadRequest, "bad user name: error")));
            } else if username == "error no message" {
                try!(Err(Status::BadRequest));
            }

            let mut cookie = Cookie::new("name".to_string(), username.to_string());
            cookie.domain = Some("localhost".to_string());
            cookie.httponly = true;
            res.cookie(cookie);
        } else {
            try!(Err((Status::BadRequest, "expected username field")))
        }

        ok!(Status::NoContent)
    }

    fn redirect(&mut self, _req: &Request, _res: &mut Response) -> Result {
        println!("waiting 3 seconds");
        thread::sleep(Duration::from_secs(3));
        ok!(Status::Found, "http://google.com")
    }

    fn streaming(&mut self, _req: &Request, _res: &mut Response) -> Result {
        stream(|_app: &mut Self, writer| {
            thread::sleep(Duration::from_secs(1));
            try!(writer.write("toto".as_bytes()));

            thread::sleep(Duration::from_secs(1));
            try!(writer.write("tata".as_bytes()));

            thread::sleep(Duration::from_secs(1));
            writer.write("titi".as_bytes())
        })
    }

}

impl MyApp {
    fn before(&mut self, req: &mut Request, _response: &mut Response) {
        debug!("hello middleware for request {:?}", req.path());
    }
}

fn files(req: &Request, _res: &mut Response) -> Result {
    let path = req.path()[1..].join("/");
    Ok(Action::SendFile("web/".to_string() + &path))
}

fn main() {
    env_logger::init().unwrap();

    let mut edge = Edge::new("0.0.0.0:3000");
    let mut router = Router::new();
    router.get("/", MyApp::home);
    router.get("/hello/:first_name/:last_name", MyApp::hello);
    router.get("/counter", MyApp::counter);

    router.get("/redirect", MyApp::redirect);
    router.get("/streaming", MyApp::streaming);

    router.post("/login", MyApp::login);

    router.get_static("/static", files);

    // registers middleware
    router.add_middleware(MyApp::before);

    // registers view views/hello.hbs
    edge.register_template("hello");

    edge.mount("/", router);
    edge.start().unwrap();
}
<commit_msg>remove warning in basic example<commit_after>#![cfg_attr(feature = "middleware", feature(specialization))]

extern crate env_logger;
#[macro_use]
extern crate log;

#[macro_use]
extern crate edge;

#[macro_use]
extern crate lazy_static;

use edge::{json, Edge, Router, Cookie, Request, Response, Result, Action, Status, stream};
use edge::header::AccessControlAllowOrigin;

use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

use std::collections::BTreeMap;

struct MyApp {
    counter: Arc<AtomicUsize>
}

lazy_static! {
    static ref COUNTER: Arc<AtomicUsize> = Default::default();
}

impl Default for MyApp {
    fn default() -> MyApp {
        debug!("MyApp::default");
        MyApp {
            counter: COUNTER.clone()
        }
    }
}

impl MyApp {

    fn home(&mut self, _req: &Request, res: &mut Response) -> Result {
        res.content_type("text/html; charset=UTF-8").header(AccessControlAllowOrigin::Any);
        let html = "<title>home</title>
Hello, world!
".to_string();
        ok!(html)
    }

    fn hello(&mut self, req: &Request, _res: &mut Response) -> Result {
        let cnt = self.counter.fetch_add(1, Ordering::SeqCst);

        let first_name = req.param("first_name").unwrap_or("John");
        let last_name = req.param("last_name").unwrap_or("Doe");

        let mut data = BTreeMap::new();
        data.insert("first_name", json::to_value(first_name));
        data.insert("last_name", json::to_value(last_name));
        data.insert("counter", json::to_value(&cnt));
        data.insert("content", json::to_value(r#"## Contents
This is a list:

- item 1
- item 2

"#));
        ok!("hello", data)
    }

    fn counter(&mut self, req: &Request, res: &mut Response) -> Result {
        let mut cookies = req.cookies();
        let name = cookies.find(|cookie| cookie.name == "name")
            .map_or("nope", |cookie| &cookie.value);
        println!("name cookie: {}", name);

        let mut data = BTreeMap::new();
        data.insert("name", json::to_value(name));
        let cnt = self.counter.load(Ordering::Relaxed);
        data.insert("counter", json::to_value(&cnt));
        res.content_type("application/json");
        ok!(json::to_value(&data))
    }

    fn login(&mut self, req: &Request, res: &mut Response) -> Result {
        let form = try!(req.form().map_err(|e| (Status::BadRequest, e.to_string())));
        if let Some(username) = form.get("username") {
            if username == "error with message" {
                try!(Err((Status::BadRequest, "bad user name: error")));
            } else if username == "error no message" {
                try!(Err(Status::BadRequest));
            }

            let mut cookie = Cookie::new("name".to_string(), username.to_string());
            cookie.domain = Some("localhost".to_string());
            cookie.httponly = true;
            res.cookie(cookie);
        } else {
            try!(Err((Status::BadRequest, "expected username field")))
        }

        ok!(Status::NoContent)
    }

    fn redirect(&mut self, _req: &Request, _res: &mut Response) -> Result {
        println!("waiting 3 seconds");
        thread::sleep(Duration::from_secs(3));
        ok!(Status::Found, "http://google.com")
    }

    fn streaming(&mut self, _req: &Request, _res: &mut Response) -> Result {
        stream(|_app: &mut Self, writer| {
            thread::sleep(Duration::from_secs(1));
            try!(writer.write("toto".as_bytes()));

            thread::sleep(Duration::from_secs(1));
            try!(writer.write("tata".as_bytes()));

            thread::sleep(Duration::from_secs(1));
            writer.write("titi".as_bytes())
        })
    }

}

impl MyApp {
    fn before(&mut self, req: &mut Request, _response: &mut Response) {
        debug!("hello middleware for request {:?}", req.path());
    }
}

fn files(req: &Request, _res: &mut Response) -> Result {
    let path = req.path()[1..].join("/");
    Ok(Action::SendFile("web/".to_string() + &path))
}

fn main() {
    env_logger::init().unwrap();

    let mut edge = Edge::new("0.0.0.0:3000");
    let mut router = Router::new();
    router.get("/", MyApp::home);
    router.get("/hello/:first_name/:last_name", MyApp::hello);
    router.get("/counter", MyApp::counter);

    router.get("/redirect", MyApp::redirect);
    router.get("/streaming", MyApp::streaming);

    router.post("/login", MyApp::login);

    router.get_static("/static", files);

    // registers middleware
    router.add_middleware(MyApp::before);

    // registers view views/hello.hbs
    edge.register_template("hello");

    edge.mount("/", router);
    edge.start().unwrap();
}
<|endoftext|>


<commit_before>extern crate termion;

use termion::{color, style};

fn main() {
    println!("{}Red", color::Fg(color::Red));
    println!("{}Blue", color::Fg(color::Blue));
    println!("{}Blue'n'Bold{}", style::Bold, style::Reset);
    println!("{}Just plain italic", style::Italic);
}
<commit_msg>Reset style in color example before exit (#138)<commit_after>extern crate termion;

use termion::{color, style};

fn main() {
    println!("{}Red", color::Fg(color::Red));
    println!("{}Blue", color::Fg(color::Blue));
    println!("{}Blue'n'Bold{}", style::Bold, style::Reset);
    println!("{}Just plain italic{}", style::Italic, style::Reset);
}
<|endoftext|>


<commit_before><commit_msg>updated to match latest glfw-rs<commit_after><|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use super::model;
use regex;
use rs_es;
use rs_es::query::Query as rs_q;
use rs_es::operations::search::SearchResult;
use rs_es::units as rs_u;
use mimir;
use serde_json;
use serde;

fn build_rs_client(cnx: &String) -> rs_es::Client {
    let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
    let cap = re.captures(&cnx).unwrap();
    let host = cap.name("host").unwrap().as_str();
    let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();

    rs_es::Client::new(&host, port)
}

/// takes a ES json blob and build a Place from it
/// it uses the _type field of ES to know which type of the Place enum to fill
pub fn make_place(doc_type: String, value: Option<Box<serde_json::Value>>) -> Option<mimir::Place> {
    value.and_then(|v| {
        fn convert<T: serde::Deserialize>(v: serde_json::Value,
                                          f: fn(T) -> mimir::Place)
                                          -> Option<mimir::Place> {
            serde_json::from_value::<T>(v)
                .map_err(|err| warn!("Impossible to load ES result: {}", err))
                .ok()
                .map(f)
        }
        match doc_type.as_ref() {
            "addr" => convert(*v, mimir::Place::Addr),
            "street" => convert(*v, mimir::Place::Street),
            "admin" => convert(*v, mimir::Place::Admin),
            "poi" => convert(*v, mimir::Place::Poi),
            "stop" => convert(*v, mimir::Place::Stop),
            _ => {
                warn!("unknown ES return value, _type field = {}", doc_type);
                None
            }
        }
    })
}

fn build_query(q: &str,
               match_type: &str,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> rs_es::query::Query {
    use rs_es::query::functions::Function;
    let boost_addr = rs_q::build_term("_type", "addr").with_boost(1000).build();
    let boost_match_query = rs_q::build_multi_match(vec![match_type.to_string(),
                                                         "zip_codes.prefix".to_string()],
                                                    q.to_string())
        .with_boost(100)
        .build();

    let mut should_query = vec![boost_addr, boost_match_query];
    if let &Some(ref c) = coord {
        // if we have coordinate, we boost we result near this coordinate
        let boost_on_proximity =
            rs_q::build_function_score()
                .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
                .with_boost(500)
                .with_function(Function::build_decay("coord",
                                           rs_u::Location::LatLon(c.lat, c.lon),
                                           rs_u::Distance::new(50f64,
                                                               rs_u::DistanceUnit::Kilometer))
                                   .build_exp())
                .build();
        should_query.push(boost_on_proximity);
    } else {
        // if we don't have coords, we take the field `weight` into account
        let boost_on_weight = rs_q::build_function_score()
            .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
            .with_boost(300)
            .with_query(rs_q::build_match_all().build())
            .with_function(Function::build_field_value_factor("weight")
                .with_factor(1)
                .with_modifier(rs_es::query::functions::Modifier::Log1p)
                .build())
            .build();
        should_query.push(boost_on_weight);
    }

    let sub_query = rs_q::build_bool()
        .with_should(should_query)
        .build();

    let mut must = vec![rs_q::build_multi_match(vec![match_type.to_string(),
        "zip_codes.prefix".to_string()], q.to_string())
             .with_minimum_should_match(rs_es::query::MinimumShouldMatch::from(90f64)).build()];

    if let Some(s) = shape {
        must.push(rs_q::build_geo_polygon("coord", s).build());
    }

    // filter to handle house number
    // we either want:
    // * to exactly match the document house_number
    // * or that the document has no house_number
    let filter = rs_q::build_bool()
        .with_should(vec![rs_q::build_bool()
                              .with_must_not(rs_q::build_exists("house_number").build())
                              .build(),
                          rs_q::build_match("house_number", q.to_string()).build()])
        .with_must(must)
        .build();

    rs_q::build_bool()
        .with_must(vec![sub_query])
        .with_filter(filter)
        .build()
}

fn query(q: &str,
         cnx: &str,
         match_type: &str,
         offset: u64,
         limit: u64,
         coord: &Option<model::Coord>,
         shape: Option<Vec<rs_es::units::Location>>)
         -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    let query = build_query(q, match_type, coord, shape);

    let mut client = build_rs_client(&cnx.to_string());

    let result: SearchResult<serde_json::Value> = try!(client.search_query()
        .with_indexes(&["munin"])
        .with_query(&query)
        .with_from(offset)
        .with_size(limit)
        .send());

    debug!("{} documents found", result.hits.total);

    // for the moment rs-es does not handle enum Document,
    // so we need to convert the ES glob to a Place
    Ok(result.hits
        .hits
        .into_iter()
        .filter_map(|hit| make_place(hit.doc_type, hit.source))
        .collect())
}

fn query_prefix(q: &str,
                cnx: &str,
                offset: u64,
                limit: u64,
                coord: &Option<model::Coord>,
                shape: Option<Vec<rs_es::units::Location>>)
                -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    query(&q, cnx, "label.prefix", offset, limit, coord, shape)
}

fn query_ngram(q: &str,
               cnx: &str,
               offset: u64,
               limit: u64,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    query(&q, cnx, "label.ngram", offset, limit, coord, shape)
}

pub fn autocomplete(q: &str,
                    offset: u64,
                    limit: u64,
                    coord: Option<model::Coord>,
                    cnx: &str,
                    shape: Option<Vec<(f64, f64)>>)
                    -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    // First search with match = "name.prefix".
    // If no result then another search with match = "name.ngram"
    fn make_shape(shape: &Option<Vec<(f64, f64)>>) -> Option<Vec<rs_es::units::Location>> {
        shape.as_ref().map(|v| v.iter().map(|&l| l.into()).collect())
    }

    let results = try!(query_prefix(&q, cnx, offset, limit, &coord, make_shape(&shape)));
    if results.is_empty() {
        query_ngram(&q, cnx, offset, limit, &coord, make_shape(&shape))
    } else {
        Ok(results)
    }
}
<commit_msg>relax the minumum match filter<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use super::model;
use regex;
use rs_es;
use rs_es::query::Query as rs_q;
use rs_es::operations::search::SearchResult;
use rs_es::units as rs_u;
use mimir;
use serde_json;
use serde;

fn build_rs_client(cnx: &String) -> rs_es::Client {
    let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
    let cap = re.captures(&cnx).unwrap();
    let host = cap.name("host").unwrap().as_str();
    let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();

    rs_es::Client::new(&host, port)
}

/// takes a ES json blob and build a Place from it
/// it uses the _type field of ES to know which type of the Place enum to fill
pub fn make_place(doc_type: String, value: Option<Box<serde_json::Value>>) -> Option<mimir::Place> {
    value.and_then(|v| {
        fn convert<T: serde::Deserialize>(v: serde_json::Value,
                                          f: fn(T) -> mimir::Place)
                                          -> Option<mimir::Place> {
            serde_json::from_value::<T>(v)
                .map_err(|err| warn!("Impossible to load ES result: {}", err))
                .ok()
                .map(f)
        }
        match doc_type.as_ref() {
            "addr" => convert(*v, mimir::Place::Addr),
            "street" => convert(*v, mimir::Place::Street),
            "admin" => convert(*v, mimir::Place::Admin),
            "poi" => convert(*v, mimir::Place::Poi),
            "stop" => convert(*v, mimir::Place::Stop),
            _ => {
                warn!("unknown ES return value, _type field = {}", doc_type);
                None
            }
        }
    })
}

fn build_query(q: &str,
               match_type: &str,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> rs_es::query::Query {
    use rs_es::query::functions::Function;
    let boost_addr = rs_q::build_term("_type", "addr").with_boost(1000).build();
    let boost_match_query = rs_q::build_multi_match(vec![match_type.to_string(),
                                                         "zip_codes.prefix".to_string()],
                                                    q.to_string())
        .with_boost(100)
        .build();

    let mut should_query = vec![boost_addr, boost_match_query];
    if let &Some(ref c) = coord {
        // if we have coordinate, we boost we result near this coordinate
        let boost_on_proximity =
            rs_q::build_function_score()
                .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
                .with_boost(500)
                .with_function(Function::build_decay("coord",
                                           rs_u::Location::LatLon(c.lat, c.lon),
                                           rs_u::Distance::new(50f64,
                                                               rs_u::DistanceUnit::Kilometer))
                                   .build_exp())
                .build();
        should_query.push(boost_on_proximity);
    } else {
        // if we don't have coords, we take the field `weight` into account
        let boost_on_weight = rs_q::build_function_score()
            .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
            .with_boost(300)
            .with_query(rs_q::build_match_all().build())
            .with_function(Function::build_field_value_factor("weight")
                .with_factor(1)
                .with_modifier(rs_es::query::functions::Modifier::Log1p)
                .build())
            .build();
        should_query.push(boost_on_weight);
    }

    let sub_query = rs_q::build_bool()
        .with_should(should_query)
        .build();

    use rs_es::query::{CombinationMinimumShouldMatch, MinimumShouldMatch};
    let min_should_match = |min, threshold| {
        CombinationMinimumShouldMatch::new(MinimumShouldMatch::from(min),
                                           MinimumShouldMatch::from(threshold))
    };

    let mut must = vec![rs_q::build_multi_match(
        vec![match_type.to_string(),"zip_codes.prefix".to_string()],
         q.to_string())
             .with_minimum_should_match(MinimumShouldMatch::from(
                 // when we search [0, 4] fields, we need to match 90% of them
                 // when we search [5, +] fields, we only need to match 70% on them
                 // this way if the input has more fields than the documents (additional information like the country, the region, ...)
                 // they can be ignored
                 vec![min_should_match(0, 90f64), min_should_match(4, 70f64)]
                 )).build()];

    if let Some(s) = shape {
        must.push(rs_q::build_geo_polygon("coord", s).build());
    }

    // filter to handle house number
    // we either want:
    // * to exactly match the document house_number
    // * or that the document has no house_number
    let filter = rs_q::build_bool()
        .with_should(vec![rs_q::build_bool()
                              .with_must_not(rs_q::build_exists("house_number").build())
                              .build(),
                          rs_q::build_match("house_number", q.to_string()).build()])
        .with_must(must)
        .build();

    rs_q::build_bool()
        .with_must(vec![sub_query])
        .with_filter(filter)
        .build()
}

fn query(q: &str,
         cnx: &str,
         match_type: &str,
         offset: u64,
         limit: u64,
         coord: &Option<model::Coord>,
         shape: Option<Vec<rs_es::units::Location>>)
         -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    let query = build_query(q, match_type, coord, shape);

    let mut client = build_rs_client(&cnx.to_string());

    let result: SearchResult<serde_json::Value> = try!(client.search_query()
        .with_indexes(&["munin"])
        .with_query(&query)
        .with_from(offset)
        .with_size(limit)
        .send());

    debug!("{} documents found", result.hits.total);

    // for the moment rs-es does not handle enum Document,
    // so we need to convert the ES glob to a Place
    Ok(result.hits
        .hits
        .into_iter()
        .filter_map(|hit| make_place(hit.doc_type, hit.source))
        .collect())
}

fn query_prefix(q: &str,
                cnx: &str,
                offset: u64,
                limit: u64,
                coord: &Option<model::Coord>,
                shape: Option<Vec<rs_es::units::Location>>)
                -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    query(&q, cnx, "label.prefix", offset, limit, coord, shape)
}

fn query_ngram(q: &str,
               cnx: &str,
               offset: u64,
               limit: u64,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    query(&q, cnx, "label.ngram", offset, limit, coord, shape)
}

pub fn autocomplete(q: &str,
                    offset: u64,
                    limit: u64,
                    coord: Option<model::Coord>,
                    cnx: &str,
                    shape: Option<Vec<(f64, f64)>>)
                    -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    // First search with match = "name.prefix".
    // If no result then another search with match = "name.ngram"
    fn make_shape(shape: &Option<Vec<(f64, f64)>>) -> Option<Vec<rs_es::units::Location>> {
        shape.as_ref().map(|v| v.iter().map(|&l| l.into()).collect())
    }

    let results = try!(query_prefix(&q, cnx, offset, limit, &coord, make_shape(&shape)));
    if results.is_empty() {
        query_ngram(&q, cnx, offset, limit, &coord, make_shape(&shape))
    } else {
        Ok(results)
    }
}
<|endoftext|>