<commit_before>//! A UI framework for Rust based on the KISS principle: "Keep It Simple, Stupid!"
//!
//! Built on top of the [IUP GUI library for C.][iup]
//!
//! ##Note: "valid KISS-UI context"
//! All KISS-UI static widget methods will panic if called before `kiss_ui::show_gui()` is invoked or
//! after it returns.
//!
//! This is because the underlying IUP library has been either, respectively, not initialized yet
//! or already deinitialized, and attempting to interact with it in either situation will likely cause
//! undefined behavior.
//!
//! ##Note: This is a (technically) leaky abstraction.
//! Because IUP only frees all its allocations when it is deinitialized, all widgets created by KISS-UI
//! will remain in-memory until `kiss_ui::show_gui()` returns. While unbounded memory growth can
//! happen with complex applications, this should not be an issue for most use-cases.
//!
//! However, some types *do* allocate large chunks of memory, or other valuable system resources,
//! and should be manually freed when they are no longer being used.
//! This is most evident with the `Image` struct, which can allocate large backing buffers for image data.
//!
//! All types that should be manually freed expose a `.destroy()` method which should be called
//! when they are no longer being used. This can safely be called multiple times on clones of the
//! widget types^([citation needed]).
//!
//! [iup]: http://webserver2.tecgraf.puc-rio.br/iup/

extern crate libc;
extern crate iup_sys;

macro_rules! assert_kiss_running (
    () => (
        assert!(
            ::KISS_RUNNING.load(::std::sync::atomic::Ordering::Acquire),
            "No KISS-UI widget methods may be called before `kiss_ui::show_gui()` is invoked or after it returns!"
        )
    )
);

#[macro_use]
pub mod widget;

#[macro_use]
pub mod utils;

// Internal use modules
mod attrs;

// User-facing modules
#[macro_use]
pub mod callback;

pub mod base;
pub mod button;
pub mod container;
pub mod dialog;
pub mod image;
pub mod progress;
pub mod text;
pub mod timer;

use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::ptr;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

use base::BaseWidget;
use dialog::Dialog;
use widget::Widget;

use utils::cstr::AsCStr;

use widget_prelude::IUPPtr;

mod widget_prelude {
    pub use widget::{Widget, IUPWidget, Destroy, WidgetStr};
    pub type IUPPtr = *mut ::iup_sys::Ihandle;
}

/// A module that KISS-UI users can glob-import to get the most common types.
pub mod prelude {
    pub use base::BaseWidget;
    pub use dialog::Dialog;
    pub use container::Orientation;
    pub use callback::{CallbackStatus, OnClick, OnShow, OnValueChange};

    pub use widget::{Widget, Destroy};
}

static KISS_RUNNING: AtomicBool = ATOMIC_BOOL_INIT;

thread_local! { static CONTEXT: KISSContext = KISSContext::default() }

#[derive(Default)]
struct KISSContext {
    widget_store: RefCell<HashMap<String, BaseWidget>>,
    // FIXME: use Rc<()> once Rc::is_unique stabilizes
    borrowed_strs: RefCell<HashMap<IUPPtr, HashMap<&'static str, Rc<Cell<usize>>>>>,
}

impl KISSContext {
    fn assert_str_not_borrowed(widget: IUPPtr, str_: &'static str) {
        assert_kiss_running!();

        let is_borrowed = CONTEXT.with(|context|
            context.borrowed_strs.borrow()
                .get(&widget)
                .and_then(|widget_strs|
                     widget_strs.get(str_)
                        .map(|refcount| refcount.get() != 0)
                )
                .unwrap_or(false)
        );

        assert!(
            is_borrowed,
            "Cannot update the value of a string property of a widget if it's been previously borrowed!"
        );
    }

    fn str_refcount(widget: IUPPtr, str_: &'static str) -> Rc<Cell<usize>> {
        assert_kiss_running!();

        CONTEXT.with(|context|
            context.borrowed_strs.borrow_mut()
                .entry(widget).or_insert_with(HashMap::new)
                .entry(str_).or_insert_with(|| Rc::new(Cell::new(0)))
                .clone()
        )
    }

    fn store_widget<N: Into<String>, W: Widget>(name: N, widget: W) -> Option<BaseWidget> {
        CONTEXT.with(|context|
            context.widget_store.borrow_mut()
                .insert(name.into(), widget.to_base())
        )
    }

    fn load_widget<N: Borrow<str>>(name: &N) -> Option<BaseWidget> {
        CONTEXT.with(|context|
            context.widget_store.borrow().get(name.borrow()).cloned()
        )
    }

    unsafe fn clear() {
        CONTEXT.with(|context| {
            context.widget_store.borrow_mut().clear();
            context.borrowed_strs.borrow_mut().clear();
        })
    }
}

/// The entry point for KISS-UI. The closure argument should initialize and call `.show()`.
///
/// ##Blocks
/// Until all KISS-UI dialogs are closed.
///
/// ##Warning
/// No static widget methods from this crate may be called before this function is
/// invoked or after it returns, with the exception of the closure passed to this function.
///
/// While this function is blocked and the IUP event loop is running, any reachable code is
/// considered a "valid KISS-UI context" and may create and interact with widgets and dialogs.
///
/// After it returns, IUP is deinitialized and all static widget methods will panic to avoid
/// undefined behavior.
///
/// ##Note: `Send` bound
/// This closure will be called in the same thread where `show_gui()` is invoked. No threading is
/// involved.
///
/// However, without the `Send` bound it would be possible to move widget types outside
/// of the closure with safe code and interact with them after IUP has been deinitialized,
/// which would cause undefined behavior.
///
/// Since no widget types are `Send`, this bound prevents this from happening without requiring
/// all widget methods to check if they were invoked in a valid context.
pub fn show_gui<F>(init_fn: F) where F: FnOnce() -> Dialog + Send {
    assert!(
        !KISS_RUNNING.compare_and_swap(false, true, Ordering::SeqCst),
        "KISS-UI may only be running (in `kiss_ui::show_gui()`) in one thread at a time!"
    );

    unsafe {
        assert!(iup_sys::IupOpen(ptr::null(), ptr::null()) == 0);
        // Force IUP to always use UTF-8
        iup_sys::IupSetGlobal(::attrs::UTF8_MODE.as_cstr(), ::attrs::values::YES.as_cstr());
    }

    init_fn().show();

    unsafe {
        iup_sys::IupMainLoop();
        iup_sys::IupClose();
        KISSContext::clear();
    }

    KISS_RUNNING.store(false, Ordering::SeqCst);
}

<commit_msg>Fix logic error in string borrowing<commit_after>//! A UI framework for Rust based on the KISS principle: "Keep It Simple, Stupid!"
//!
//! Built on top of the [IUP GUI library for C.][iup]
//!
//! ##Note: "valid KISS-UI context"
//! All KISS-UI static widget methods will panic if called before `kiss_ui::show_gui()` is invoked or
//! after it returns.
//!
//! This is because the underlying IUP library has been either, respectively, not initialized yet
//! or already deinitialized, and attempting to interact with it in either situation will likely cause
//! undefined behavior.
//!
//! ##Note: This is a (technically) leaky abstraction.
//! Because IUP only frees all its allocations when it is deinitialized, all widgets created by KISS-UI
//! will remain in-memory until `kiss_ui::show_gui()` returns. While unbounded memory growth can
//! happen with complex applications, this should not be an issue for most use-cases.
//!
//! However, some types *do* allocate large chunks of memory, or other valuable system resources,
//! and should be manually freed when they are no longer being used.
//! This is most evident with the `Image` struct, which can allocate large backing buffers for image data.
//!
//! All types that should be manually freed expose a `.destroy()` method which should be called
//! when they are no longer being used. This can safely be called multiple times on clones of the
//! widget types^([citation needed]).
//!
//! [iup]: http://webserver2.tecgraf.puc-rio.br/iup/

extern crate libc;
extern crate iup_sys;

macro_rules! assert_kiss_running (
    () => (
        assert!(
            ::KISS_RUNNING.load(::std::sync::atomic::Ordering::Acquire),
            "No KISS-UI widget methods may be called before `kiss_ui::show_gui()` is invoked or after it returns!"
        )
    )
);

#[macro_use]
pub mod widget;

#[macro_use]
pub mod utils;

// Internal use modules
mod attrs;

// User-facing modules
#[macro_use]
pub mod callback;

pub mod base;
pub mod button;
pub mod container;
pub mod dialog;
pub mod image;
pub mod progress;
pub mod text;
pub mod timer;

use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::ptr;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

use base::BaseWidget;
use dialog::Dialog;
use widget::Widget;

use utils::cstr::AsCStr;

use widget_prelude::IUPPtr;

mod widget_prelude {
    pub use widget::{Widget, IUPWidget, Destroy, WidgetStr};
    pub type IUPPtr = *mut ::iup_sys::Ihandle;
}

/// A module that KISS-UI users can glob-import to get the most common types.
pub mod prelude {
    pub use base::BaseWidget;
    pub use dialog::Dialog;
    pub use container::Orientation;
    pub use callback::{CallbackStatus, OnClick, OnShow, OnValueChange};

    pub use widget::{Widget, Destroy};
}

static KISS_RUNNING: AtomicBool = ATOMIC_BOOL_INIT;

thread_local! { static CONTEXT: KISSContext = KISSContext::default() }

#[derive(Default)]
struct KISSContext {
    widget_store: RefCell<HashMap<String, BaseWidget>>,
    // FIXME: use Rc<()> once Rc::is_unique stabilizes
    borrowed_strs: RefCell<HashMap<IUPPtr, HashMap<&'static str, Rc<Cell<usize>>>>>,
}

impl KISSContext {
    fn assert_str_not_borrowed(widget: IUPPtr, str_: &'static str) {
        assert_kiss_running!();

        let is_borrowed = CONTEXT.with(|context|
            context.borrowed_strs.borrow()
                .get(&widget)
                .and_then(|widget_strs|
                     widget_strs.get(str_)
                        .map(|refcount| refcount.get() != 0)
                )
                .unwrap_or(false)
        );

        assert!(
            !is_borrowed,
            "Cannot update the value of a string property of a widget if it's been previously borrowed!"
        );
    }

    fn str_refcount(widget: IUPPtr, str_: &'static str) -> Rc<Cell<usize>> {
        assert_kiss_running!();

        CONTEXT.with(|context|
            context.borrowed_strs.borrow_mut()
                .entry(widget).or_insert_with(HashMap::new)
                .entry(str_).or_insert_with(|| Rc::new(Cell::new(0)))
                .clone()
        )
    }

    fn store_widget<N: Into<String>, W: Widget>(name: N, widget: W) -> Option<BaseWidget> {
        CONTEXT.with(|context|
            context.widget_store.borrow_mut()
                .insert(name.into(), widget.to_base())
        )
    }

    fn load_widget<N: Borrow<str>>(name: &N) -> Option<BaseWidget> {
        CONTEXT.with(|context|
            context.widget_store.borrow().get(name.borrow()).cloned()
        )
    }

    unsafe fn clear() {
        CONTEXT.with(|context| {
            context.widget_store.borrow_mut().clear();
            context.borrowed_strs.borrow_mut().clear();
        })
    }
}

/// The entry point for KISS-UI. The closure argument should initialize and call `.show()`.
///
/// ##Blocks
/// Until all KISS-UI dialogs are closed.
///
/// ##Warning
/// No static widget methods from this crate may be called before this function is
/// invoked or after it returns, with the exception of the closure passed to this function.
///
/// While this function is blocked and the IUP event loop is running, any reachable code is
/// considered a "valid KISS-UI context" and may create and interact with widgets and dialogs.
///
/// After it returns, IUP is deinitialized and all static widget methods will panic to avoid
/// undefined behavior.
///
/// ##Note: `Send` bound
/// This closure will be called in the same thread where `show_gui()` is invoked. No threading is
/// involved.
///
/// However, without the `Send` bound it would be possible to move widget types outside
/// of the closure with safe code and interact with them after IUP has been deinitialized,
/// which would cause undefined behavior.
///
/// Since no widget types are `Send`, this bound prevents this from happening without requiring
/// all widget methods to check if they were invoked in a valid context.
pub fn show_gui<F>(init_fn: F) where F: FnOnce() -> Dialog + Send {
    assert!(
        !KISS_RUNNING.compare_and_swap(false, true, Ordering::SeqCst),
        "KISS-UI may only be running (in `kiss_ui::show_gui()`) in one thread at a time!"
    );

    unsafe {
        assert!(iup_sys::IupOpen(ptr::null(), ptr::null()) == 0);
        // Force IUP to always use UTF-8
        iup_sys::IupSetGlobal(::attrs::UTF8_MODE.as_cstr(), ::attrs::values::YES.as_cstr());
    }

    init_fn().show();

    unsafe {
        iup_sys::IupMainLoop();
        iup_sys::IupClose();
        KISSContext::clear();
    }

    KISS_RUNNING.store(false, Ordering::SeqCst);
}

<|endoftext|>


<commit_before>//! Preferred system exit codes as defined by sysexits.h
//!
//! Exit code constants intended to be passed to
//! `std::env::set_exit_status!()` or `std::process::exit()`
//!
//! # Example:
//! ```
//! use exitcode;
//!
//! ::std::process::exit(exitcode::OK);
//! ```

/// Successful exit
pub const OK: i32 = 0;

/// The command was used incorrectly, e.g., with the
/// wrong number of arguments, a bad flag, a bad syntax
/// in a parameter, etc.
pub const USAGE: i32 = 64;

/// The input data was incorrect in some way.  This
/// should only be used for user's data and not system
/// files.
pub const DATAERR: i32 = 65;

/// An input file (not a system file) did not exist or
/// was not readable.  This could also include errors
/// like "No message" to a mailer (if it cared to
/// catch it).
pub const NOINPUT: i32 = 66;

/// The user specified did not exist.  This might be
/// used for mail addresses or remote logins.
pub const NOUSER: i32 = 67;

/// The host specified did not exist.  This is used in
/// mail addresses or network requests.
pub const NOHOST: i32 = 68;

/// A service is unavailable.  This can occur if a sup
/// port program or file does not exist.  This can also
/// be used as a catchall message when something you
/// wanted to do doesn't work, but you don't know why.
pub const UNAVAILABLE: i32 = 69;

/// An internal software error has been detected.  This
/// should be limited to non-operating system related
/// errors as possible.
pub const SOFTWARE: i32 = 70;

/// An operating system error has been detected.  This
/// is intended to be used for such things as "cannot
/// fork", "cannot create pipe", or the like.  It
/// includes things like getuid returning a user that
/// does not exist in the passwd file.
pub const OSERR: i32 = 71;

/// Some system file (e.g., /etc/passwd, /var/run/utmp,
/// etc.) does not exist, cannot be opened, or has some
/// sort of error (e.g., syntax error).
pub const OSFILE: i32 = 72;

/// A (user specified) output file cannot be created.
pub const CANTCREAT: i32 = 73;

/// An error occurred while doing I/O on some file.
pub const IOERR: i32 = 74;

/// Temporary failure, indicating something that is not
/// really an error.  In sendmail, this means that a
/// mailer (e.g.) could not create a connection, and
/// the request should be reattempted later.
pub const TEMPFAIL: i32 = 75;

/// The remote system returned something that was
/// "not possible" during a protocol exchange.
pub const PROTOCOL: i32 = 76;

/// You did not have sufficient permission to perform
/// the operation.  This is not intended for file system
/// problems, which should use `NOINPUT` or `CANTCREAT`,
/// but rather for higher level permissions.
pub const NOPERM: i32 = 77;

/// Something was found in an unconfigured or misconfigured state.
pub const CONFIG: i32 = 78;

/// Check if exit code given by `code` is successful
///
/// # Example:
/// ```
/// use exitcode;
/// assert!(exitcode::is_success(exitcode::OK));
/// assert!(!exitcode::is_success(exitcode::USAGE));
/// ```
pub fn is_success(code: i32) -> bool {
    code == OK
}

/// Check if exit code given by `code` is an error
///
/// # Example:
/// ```
/// use exitcode;
/// assert!(exitcode::is_error(exitcode::USAGE));
/// assert!(!exitcode::is_error(exitcode::OK));
/// ```
pub fn is_error(code: i32) -> bool {
    !is_success(code)
}
<commit_msg>Don't mention `std::env::set_exit_status()`<commit_after>//! Preferred system exit codes as defined by sysexits.h
//!
//! Exit code constants intended to be passed to
//! `std::process::exit()`
//!
//! # Example:
//! ```
//! use exitcode;
//!
//! ::std::process::exit(exitcode::OK);
//! ```

/// Successful exit
pub const OK: i32 = 0;

/// The command was used incorrectly, e.g., with the
/// wrong number of arguments, a bad flag, a bad syntax
/// in a parameter, etc.
pub const USAGE: i32 = 64;

/// The input data was incorrect in some way.  This
/// should only be used for user's data and not system
/// files.
pub const DATAERR: i32 = 65;

/// An input file (not a system file) did not exist or
/// was not readable.  This could also include errors
/// like "No message" to a mailer (if it cared to
/// catch it).
pub const NOINPUT: i32 = 66;

/// The user specified did not exist.  This might be
/// used for mail addresses or remote logins.
pub const NOUSER: i32 = 67;

/// The host specified did not exist.  This is used in
/// mail addresses or network requests.
pub const NOHOST: i32 = 68;

/// A service is unavailable.  This can occur if a sup
/// port program or file does not exist.  This can also
/// be used as a catchall message when something you
/// wanted to do doesn't work, but you don't know why.
pub const UNAVAILABLE: i32 = 69;

/// An internal software error has been detected.  This
/// should be limited to non-operating system related
/// errors as possible.
pub const SOFTWARE: i32 = 70;

/// An operating system error has been detected.  This
/// is intended to be used for such things as "cannot
/// fork", "cannot create pipe", or the like.  It
/// includes things like getuid returning a user that
/// does not exist in the passwd file.
pub const OSERR: i32 = 71;

/// Some system file (e.g., /etc/passwd, /var/run/utmp,
/// etc.) does not exist, cannot be opened, or has some
/// sort of error (e.g., syntax error).
pub const OSFILE: i32 = 72;

/// A (user specified) output file cannot be created.
pub const CANTCREAT: i32 = 73;

/// An error occurred while doing I/O on some file.
pub const IOERR: i32 = 74;

/// Temporary failure, indicating something that is not
/// really an error.  In sendmail, this means that a
/// mailer (e.g.) could not create a connection, and
/// the request should be reattempted later.
pub const TEMPFAIL: i32 = 75;

/// The remote system returned something that was
/// "not possible" during a protocol exchange.
pub const PROTOCOL: i32 = 76;

/// You did not have sufficient permission to perform
/// the operation.  This is not intended for file system
/// problems, which should use `NOINPUT` or `CANTCREAT`,
/// but rather for higher level permissions.
pub const NOPERM: i32 = 77;

/// Something was found in an unconfigured or misconfigured state.
pub const CONFIG: i32 = 78;

/// Check if exit code given by `code` is successful
///
/// # Example:
/// ```
/// use exitcode;
/// assert!(exitcode::is_success(exitcode::OK));
/// assert!(!exitcode::is_success(exitcode::USAGE));
/// ```
pub fn is_success(code: i32) -> bool {
    code == OK
}

/// Check if exit code given by `code` is an error
///
/// # Example:
/// ```
/// use exitcode;
/// assert!(exitcode::is_error(exitcode::USAGE));
/// assert!(!exitcode::is_error(exitcode::OK));
/// ```
pub fn is_error(code: i32) -> bool {
    !is_success(code)
}
<|endoftext|>


<commit_before>#![deny(
    absolute_paths_not_starting_with_crate,
    ambiguous_associated_items,
    anonymous_parameters,
    arithmetic_overflow,
    array_into_iter,
    asm_sub_register,
    bindings_with_variant_name,
    broken_intra_doc_links,
    cenum_impl_drop_cast,
    clashing_extern_declarations,
    coherence_leak_check,
    conflicting_repr_hints,
    confusable_idents,
    const_err,
    dead_code,
    deprecated,
    deprecated_in_future,
    ellipsis_inclusive_range_patterns,
    explicit_outlives_requirements,
    exported_private_dependencies,
    ill_formed_attribute_input,
    illegal_floating_point_literal_pattern,
    improper_ctypes,
    improper_ctypes_definitions,
    incomplete_features,
    incomplete_include,
    indirect_structural_match,
    inline_no_sanitize,
    invalid_codeblock_attributes,
    invalid_type_param_default,
    invalid_value,
    irrefutable_let_patterns,
    keyword_idents,
    late_bound_lifetime_arguments,
    macro_expanded_macro_exports_accessed_by_absolute_paths,
    meta_variable_misuse,
    missing_copy_implementations,
    missing_crate_level_docs,
    missing_docs,
    mixed_script_confusables,
    mutable_borrow_reservation_conflict,
    mutable_transmutes,
    no_mangle_const_items,
    no_mangle_generic_items,
    non_ascii_idents,
    non_camel_case_types,
    non_shorthand_field_patterns,
    non_snake_case,
    non_upper_case_globals,
    order_dependent_trait_objects,
    overflowing_literals,
    overlapping_patterns,
    path_statements,
    patterns_in_fns_without_body,
    private_doc_tests,
    private_in_public,
    proc_macro_derive_resolution_fallback,
    pub_use_of_private_extern_crate,
    redundant_semicolons,
    safe_packed_borrows,
    soft_unstable,
    stable_features,
    trivial_bounds,
    trivial_casts,
    trivial_numeric_casts,
    type_alias_bounds,
    tyvar_behind_raw_pointer,
    unaligned_references,
    uncommon_codepoints,
    unconditional_panic,
    unconditional_recursion,
    unknown_crate_types,
    unnameable_test_items,
    unreachable_code,
    unreachable_patterns,
    unreachable_pub,
    unsafe_code,
    unstable_features,
    unstable_name_collisions,
    unused_allocation,
    unused_assignments,
    unused_attributes,
    unused_braces,
    unused_comparisons,
    unused_crate_dependencies,
    unused_doc_comments,
    unused_extern_crates,
    unused_features,
    unused_import_braces,
    unused_imports,
    unused_labels,
    unused_lifetimes,
    unused_macros,
    unused_must_use,
    unused_mut,
    unused_parens,
    unused_qualifications,
    unused_unsafe,
    unused_variables,
    where_clauses_object_safety
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
    bare_trait_objects,
    box_pointers,
    elided_lifetimes_in_paths,
    missing_doc_code_examples,
    missing_debug_implementations,
    single_use_lifetimes,
    unused_results,
    variant_size_differences,
    warnings,
    renamed_and_removed_lints
)]

//! # simple_redis
//!
//! Simple and resilient [redis](https://redis.io/) client based on [redis-rs](https://crates.io/crates/redis) with
//! internal connection and subscription handling.
//!
//! This library provides a very basic, simple API for the most common redis operations.

//! While not as comprehensive or flexiable as [redis-rs](https://crates.io/crates/redis),
//! it does provide a simpler api for most common use cases and operations as well as automatic and resilient internal
//! connection and subscription (pubsub) handling.

//! In addition, the entire API is accessible via redis client and there is no need to manage connection or pubsub
//! instances in parallel.

//!
//! ## Connection Resiliency
//!
//! Connection resiliency is managed by verifying the internally managed connection before every operation against the
//! redis server.

//! In case of any connection issue, a new connection will be allocated to ensure the operation is invoked on a valid
//! connection only.

//! However, this comes at a small performance cost of PING operation to the redis server.

//!
//! ## Subscription Resiliency
//!
//! Subscription resiliency is ensured by recreating the internal pubsub and issuing new subscription requests
//! automatically in case of any error while fetching a message from the subscribed channels.
//!
//! # Examples
//!
//! ## Initialization and Simple Operations
//!
//! ```
//! fn main() {
//!     match simple_redis::create("redis://127.0.0.1:6379/") {
//!         Ok(mut client) =>  {
//!             println!("Created Redis Client");
//!
//!             match client.set("my_key", "my_value") {
//!                 Err(error) => println!("Unable to set value in Redis: {}", error),
//!                 _ => println!("Value set in Redis")
//!             };
//!
//!             match client.get_string("my_key") {
//!                 Ok(value) => println!("Read value from Redis: {}", value),
//!                 Err(error) => println!("Unable to get value from Redis: {}", error)
//!             };
//!
//!             match client.set("my_numeric_key", 255.5) {
//!                 Err(error) => println!("Unable to set value in Redis: {}", error),
//!                 _ => println!("Value set in Redis")
//!             };
//!
//!             match client.get::<f32>("my_numeric_key") {
//!                 Ok(value) => println!("Read value from Redis: {}", value),
//!                 Err(error) => println!("Unable to get value from Redis: {}", error)
//!             };
//!
//!             match client.hgetall("my_map") {
//!                 Ok(map) => {
//!                     match map.get("my_field") {
//!                         Some(value) => println!("Got field value from map: {}", value),
//!                         None => println!("Map field is emtpy"),
//!                     }
//!                 },
//!                 Err(error) => println!("Unable to read map from Redis: {}", error),
//!             };
//!
//!             /// run some command that is not built in the library
//!             match client.run_command::<String>("ECHO", vec!["testing"]) {
//!                 Ok(value) => assert_eq!(value, "testing"),
//!                 _ => panic!("test error"),
//!             };
//!
//!             /// publish messages
//!             let result = client.publish("news_channel", "test message");
//!             assert!(result.is_ok());
//!         },
//!         Err(error) => println!("Unable to create Redis client: {}", error)
//!     }
//! }
//! ```
//!
//! ## Subscription Flow
//!
//! ```rust,no_run
//! use simple_redis::{Interrupts, Message};
//!
//! fn main() {
//!     match simple_redis::create("redis://127.0.0.1:6379/") {
//!         Ok(mut client) =>  {
//!             println!("Created Redis Client");
//!
//!             let mut result = client.subscribe("important_notifications");
//!             assert!(result.is_ok());
//!             result = client.psubscribe("*_notifications");
//!             assert!(result.is_ok());
//!
//!             // fetch messages from all subscriptions
//!             client.fetch_messages(
//!                 &mut |message: Message| -> bool {
//!                     let payload : String = message.get_payload().unwrap();
//!                     println!("Got message: {}", payload);
//!
//!                     // continue fetching
//!                     false
//!                 },
//!                 &mut || -> Interrupts { Interrupts::new() },
//!             ).unwrap();
//!         },
//!         Err(error) => println!("Unable to create Redis client: {}", error)
//!     }
//! }
//! ```
//!
//! ## Closing Connection
//!
//! ```rust
//! fn main() {
//!     match simple_redis::create("redis://127.0.0.1:6379/") {
//!         Ok(mut client) =>  {
//!             println!("Created Redis Client");
//!
//!             match client.set("my_key", "my_value") {
//!                 Err(error) => println!("Unable to set value in Redis: {}", error),
//!                 _ => println!("Value set in Redis")
//!             };
//!
//!             match client.quit() {
//!                 Err(error) => println!("Error: {}", error),
//!                 _ => println!("Connection Closed.")
//!             }
//!         },
//!         Err(error) => println!("Unable to create Redis client: {}", error)
//!     }
//! }
//! ```
//!
//! # Installation
//! In order to use this library, just add it as a dependency:
//!
//! ```ini
//! [dependencies]
//! simple_redis = "*"
//! ```
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/simple_redis/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/simple_redis/blob/master/LICENSE) open source license.
//!

#[cfg(test)]
#[path = "./lib_test.rs"]
mod lib_test;

#[cfg(doctest)]
doc_comment::doctest!("../README.md");

pub mod client;
mod commands;
mod connection;
mod subscriber;
pub mod types;

/// Error Type
pub type RedisError = types::RedisError;

/// Error Info
pub type ErrorInfo = types::ErrorInfo;

/// PubSub message
pub type Message = types::Message;

/// Blocking operations interrupts
pub type Interrupts = types::Interrupts;

/// Redis result which either holds a value or a Redis error
pub type RedisResult<T> = types::RedisResult<T>;

/// Constructs a new redis client.

/// The redis connection string must be in the following format: `redis://[:<passwd>@]<hostname>[:port][/<db>]`
///
/// # Arguments
///
/// * `connection_string` - The connection string in the format of: `redis://[:<passwd>@]<hostname>[:port][/<db>]`
///
/// # Example
///
/// ```
/// extern crate simple_redis;
///
/// fn main() {
///     match simple_redis::create("redis://127.0.0.1:6379/") {
///         Ok(client) => println!("Created Redis Client"),
///         Err(error) => println!("Unable to create Redis client: {}", error)
///     }
/// }
/// ```
pub fn create(connection_string: &str) -> Result<client::Client, RedisError> {
    client::create(connection_string)
}
<commit_msg>rust upgrade<commit_after>#![deny(
    absolute_paths_not_starting_with_crate,
    ambiguous_associated_items,
    anonymous_parameters,
    arithmetic_overflow,
    array_into_iter,
    asm_sub_register,
    bindings_with_variant_name,
    broken_intra_doc_links,
    cenum_impl_drop_cast,
    clashing_extern_declarations,
    coherence_leak_check,
    conflicting_repr_hints,
    confusable_idents,
    const_err,
    const_evaluatable_unchecked,
    const_item_mutation,
    dead_code,
    deprecated,
    deprecated_in_future,
    drop_bounds,
    ellipsis_inclusive_range_patterns,
    explicit_outlives_requirements,
    exported_private_dependencies,
    function_item_references,
    ill_formed_attribute_input,
    illegal_floating_point_literal_pattern,
    improper_ctypes,
    improper_ctypes_definitions,
    incomplete_features,
    incomplete_include,
    indirect_structural_match,
    inline_no_sanitize,
    invalid_codeblock_attributes,
    invalid_html_tags,
    invalid_type_param_default,
    invalid_value,
    irrefutable_let_patterns,
    keyword_idents,
    late_bound_lifetime_arguments,
    macro_expanded_macro_exports_accessed_by_absolute_paths,
    meta_variable_misuse,
    missing_copy_implementations,
    missing_crate_level_docs,
    missing_docs,
    mixed_script_confusables,
    mutable_borrow_reservation_conflict,
    mutable_transmutes,
    no_mangle_const_items,
    no_mangle_generic_items,
    non_ascii_idents,
    non_camel_case_types,
    non_shorthand_field_patterns,
    non_snake_case,
    non_upper_case_globals,
    nontrivial_structural_match,
    order_dependent_trait_objects,
    overflowing_literals,
    overlapping_patterns,
    path_statements,
    patterns_in_fns_without_body,
    pointer_structural_match,
    private_doc_tests,
    private_in_public,
    proc_macro_derive_resolution_fallback,
    pub_use_of_private_extern_crate,
    redundant_semicolons,
    safe_packed_borrows,
    soft_unstable,
    stable_features,
    temporary_cstring_as_ptr,
    trivial_bounds,
    trivial_casts,
    trivial_numeric_casts,
    type_alias_bounds,
    tyvar_behind_raw_pointer,
    unaligned_references,
    uncommon_codepoints,
    unconditional_panic,
    unconditional_recursion,
    uninhabited_static,
    unknown_crate_types,
    unnameable_test_items,
    unreachable_code,
    unreachable_patterns,
    unreachable_pub,
    unsafe_code,
    unstable_features,
    unstable_name_collisions,
    unused_allocation,
    unused_assignments,
    unused_attributes,
    unused_braces,
    unused_comparisons,
    unused_crate_dependencies,
    unused_doc_comments,
    unused_extern_crates,
    unused_features,
    unused_import_braces,
    unused_imports,
    unused_labels,
    unused_lifetimes,
    unused_macros,
    unused_must_use,
    unused_mut,
    unused_parens,
    unused_qualifications,
    unused_unsafe,
    unused_variables,
    where_clauses_object_safety,
    while_true
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
    bare_trait_objects,
    box_pointers,
    elided_lifetimes_in_paths,
    missing_doc_code_examples,
    missing_debug_implementations,
    single_use_lifetimes,
    unused_results,
    variant_size_differences,
    warnings,
    renamed_and_removed_lints
)]

//! # simple_redis
//!
//! Simple and resilient [redis](https://redis.io/) client based on [redis-rs](https://crates.io/crates/redis) with
//! internal connection and subscription handling.
//!
//! This library provides a very basic, simple API for the most common redis operations.

//! While not as comprehensive or flexiable as [redis-rs](https://crates.io/crates/redis),
//! it does provide a simpler api for most common use cases and operations as well as automatic and resilient internal
//! connection and subscription (pubsub) handling.

//! In addition, the entire API is accessible via redis client and there is no need to manage connection or pubsub
//! instances in parallel.

//!
//! ## Connection Resiliency
//!
//! Connection resiliency is managed by verifying the internally managed connection before every operation against the
//! redis server.

//! In case of any connection issue, a new connection will be allocated to ensure the operation is invoked on a valid
//! connection only.

//! However, this comes at a small performance cost of PING operation to the redis server.

//!
//! ## Subscription Resiliency
//!
//! Subscription resiliency is ensured by recreating the internal pubsub and issuing new subscription requests
//! automatically in case of any error while fetching a message from the subscribed channels.
//!
//! # Examples
//!
//! ## Initialization and Simple Operations
//!
//! ```
//! fn main() {
//!     match simple_redis::create("redis://127.0.0.1:6379/") {
//!         Ok(mut client) =>  {
//!             println!("Created Redis Client");
//!
//!             match client.set("my_key", "my_value") {
//!                 Err(error) => println!("Unable to set value in Redis: {}", error),
//!                 _ => println!("Value set in Redis")
//!             };
//!
//!             match client.get_string("my_key") {
//!                 Ok(value) => println!("Read value from Redis: {}", value),
//!                 Err(error) => println!("Unable to get value from Redis: {}", error)
//!             };
//!
//!             match client.set("my_numeric_key", 255.5) {
//!                 Err(error) => println!("Unable to set value in Redis: {}", error),
//!                 _ => println!("Value set in Redis")
//!             };
//!
//!             match client.get::<f32>("my_numeric_key") {
//!                 Ok(value) => println!("Read value from Redis: {}", value),
//!                 Err(error) => println!("Unable to get value from Redis: {}", error)
//!             };
//!
//!             match client.hgetall("my_map") {
//!                 Ok(map) => {
//!                     match map.get("my_field") {
//!                         Some(value) => println!("Got field value from map: {}", value),
//!                         None => println!("Map field is emtpy"),
//!                     }
//!                 },
//!                 Err(error) => println!("Unable to read map from Redis: {}", error),
//!             };
//!
//!             /// run some command that is not built in the library
//!             match client.run_command::<String>("ECHO", vec!["testing"]) {
//!                 Ok(value) => assert_eq!(value, "testing"),
//!                 _ => panic!("test error"),
//!             };
//!
//!             /// publish messages
//!             let result = client.publish("news_channel", "test message");
//!             assert!(result.is_ok());
//!         },
//!         Err(error) => println!("Unable to create Redis client: {}", error)
//!     }
//! }
//! ```
//!
//! ## Subscription Flow
//!
//! ```rust,no_run
//! use simple_redis::{Interrupts, Message};
//!
//! fn main() {
//!     match simple_redis::create("redis://127.0.0.1:6379/") {
//!         Ok(mut client) =>  {
//!             println!("Created Redis Client");
//!
//!             let mut result = client.subscribe("important_notifications");
//!             assert!(result.is_ok());
//!             result = client.psubscribe("*_notifications");
//!             assert!(result.is_ok());
//!
//!             // fetch messages from all subscriptions
//!             client.fetch_messages(
//!                 &mut |message: Message| -> bool {
//!                     let payload : String = message.get_payload().unwrap();
//!                     println!("Got message: {}", payload);
//!
//!                     // continue fetching
//!                     false
//!                 },
//!                 &mut || -> Interrupts { Interrupts::new() },
//!             ).unwrap();
//!         },
//!         Err(error) => println!("Unable to create Redis client: {}", error)
//!     }
//! }
//! ```
//!
//! ## Closing Connection
//!
//! ```rust
//! fn main() {
//!     match simple_redis::create("redis://127.0.0.1:6379/") {
//!         Ok(mut client) =>  {
//!             println!("Created Redis Client");
//!
//!             match client.set("my_key", "my_value") {
//!                 Err(error) => println!("Unable to set value in Redis: {}", error),
//!                 _ => println!("Value set in Redis")
//!             };
//!
//!             match client.quit() {
//!                 Err(error) => println!("Error: {}", error),
//!                 _ => println!("Connection Closed.")
//!             }
//!         },
//!         Err(error) => println!("Unable to create Redis client: {}", error)
//!     }
//! }
//! ```
//!
//! # Installation
//! In order to use this library, just add it as a dependency:
//!
//! ```ini
//! [dependencies]
//! simple_redis = "*"
//! ```
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/simple_redis/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/simple_redis/blob/master/LICENSE) open source license.
//!

#[cfg(test)]
#[path = "./lib_test.rs"]
mod lib_test;

#[cfg(doctest)]
doc_comment::doctest!("../README.md");

pub mod client;
mod commands;
mod connection;
mod subscriber;
pub mod types;

/// Error Type
pub type RedisError = types::RedisError;

/// Error Info
pub type ErrorInfo = types::ErrorInfo;

/// PubSub message
pub type Message = types::Message;

/// Blocking operations interrupts
pub type Interrupts = types::Interrupts;

/// Redis result which either holds a value or a Redis error
pub type RedisResult<T> = types::RedisResult<T>;

/// Constructs a new redis client.

/// The redis connection string must be in the following format: `redis://[:<passwd>@]<hostname>[:port][/<db>]`
///
/// # Arguments
///
/// * `connection_string` - The connection string in the format of: `redis://[:<passwd>@]<hostname>[:port][/<db>]`
///
/// # Example
///
/// ```
/// extern crate simple_redis;
///
/// fn main() {
///     match simple_redis::create("redis://127.0.0.1:6379/") {
///         Ok(client) => println!("Created Redis Client"),
///         Err(error) => println!("Unable to create Redis client: {}", error)
///     }
/// }
/// ```
pub fn create(connection_string: &str) -> Result<client::Client, RedisError> {
    client::create(connection_string)
}
<|endoftext|>


<commit_before>//! `icndb` provides a simple interface to `api.icndb.com` and is
//! designed especially for use with `fun`. Extracting this functionality
//! into a library grants us greater flexibility with regard to our
//! base application and will permit a large number of improvements
//! in the future.
//!
//! ** Examples should go here. **

#![feature(box_syntax, io, plugin)]

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

use hyper::Client;
use rustc_serialize::json;
use std::io::Read;

/// Wraps an API response from the `api.icndb.com`. The authors'
/// intent appears to have been to provide an interface for both
/// failed and successful requests, but it has been difficult to
/// represent the full wrapper in Rust, and the wrapper adds no
/// real value.
#[derive(RustcDecodable, RustcEncodable)]
struct ApiResponseWrapper {
    // type: String, // terrible field name
    value: ApiResponse,
}

/// Represents a single joke provided by the ICNDB. The `id` field
/// uniquely identifies this specific joke, which allows the user
/// to get this joke again at a later time if he or she so desires.
#[derive(RustcDecodable, RustcEncodable)]
pub struct ApiResponse {
    pub id: u64,
    pub joke: String,
    pub categories: Box<[String]>
}

/// Returns an option value containing a random joke from the API
/// or, failing that, None.
pub fn next() -> Option<ApiResponse> {
    unwrap_response(execute_request("http://api.icndb.com/jokes/random"))
}

/// Returns an option value containing a random joke from the API
/// using the names supplied to the function instead of the default
/// name (Chuck Norris) or, failing that, None.
pub fn next_with_names(first: &str, last: &str) -> Option<ApiResponse> {
    unwrap_response(execute_request(&format!("http://api.icndb.com/jokes/random?firstName={}&lastName={}", first, last)))
}

/// Returns an option value containing a specified joke from the API
/// or, failing that, None.
pub fn get_by_id(id: u64) -> Option<ApiResponse> {
    unwrap_response(execute_request(&format!("http://api.icndb.com/jokes/{}", id)))
}

/// Returns an option value containing a specified joke from the API
/// using the names supplied to the function instead of the default
/// name (Chuck Norris) or, failing that, None.
pub fn get_by_id_with_names(id: u64, first: &str, last: &str) -> Option<ApiResponse> {
    unwrap_response(
        execute_request(
            &format!(
                "http://api.icndb.com/jokes/{}?firstName={}&lastName={}",
                id,
                first,
                last)))
}

/// Parses the response returned by a query against the ICNDB API
/// into an ApiResponse or, failing that, None.
fn unwrap_response(response: Option<String>) -> Option<ApiResponse> {
    let raw_response = match response {
        Some(response) => response,
        None => return None,
    };

    match json::decode::<ApiResponseWrapper>(&raw_response) {
        Ok(result) => unescape_content(result.value),
        _ => None
    }
}

/// Unescape HTML entities found in joke contents.
///
/// The ICNDB represents some values as HTML entities in the json
/// packets returned to the caller and rustc_deserialize does not
/// unescape these entities upon deserializing the json packet.
/// This function deals with that by taking the (potentially) escaped
/// values and unescaping any HTML entities contained therein before
/// returning a new ApiResponse struct containing the unescaped
/// values.
///
/// ** Entities handled include: **
/// - "
///
/// Hopefully we won't discover anymore.
fn unescape_content(response: ApiResponse) -> Option<ApiResponse> {
    if response.joke.contains(""") {
        Some(ApiResponse {
            id: response.id,
            joke: response.joke.replace(""", "\""),
            categories: response.categories
        })
    } else {
        Some(response)
    }
}

/// Executes an arbitrary request against the ICNDB API.
fn execute_request(request: &str) -> Option<String> {
    let mut client = Client::new();
    let mut response = match client.get(request).send() {
        Ok(res) => res,
        _ => return None
    };

    let mut content = String::new();
    match response.read_to_string(&mut content) {
       Ok(()) => Some(content),
        _ => None
    }
}
<commit_msg>Add doc sample.<commit_after>//! `icndb` provides a simple interface to `api.icndb.com` and is
//! designed especially for use with `fun`. Extracting this functionality
//! into a library grants us greater flexibility with regard to our
//! base application and will permit a large number of improvements
//! in the future.
//!
//! ## Example
//!
//! The code below calls the API to get a random joke with the custom
//! name "Maximus Hardcorion", because why would you not?
//!
//! ```
//! extern crate icndb;
//!
//! let response = icndb::next_with_names("Maximus", "Hardcorion").unwrap();
//!
//! assert!(response.joke.contains("Maximus Hardcorion"));
//! ```
//!
//! The big thing to keep in mind, here, is that Maximus Hardcorion is
//! Chuck Norris' Latin name.

#![feature(box_syntax, io, plugin)]

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

use hyper::Client;
use rustc_serialize::json;
use std::io::Read;

/// Wraps an API response from the `api.icndb.com`. The authors'
/// intent appears to have been to provide an interface for both
/// failed and successful requests, but it has been difficult to
/// represent the full wrapper in Rust, and the wrapper adds no
/// real value.
#[derive(RustcDecodable, RustcEncodable)]
struct ApiResponseWrapper {
    // type: String, // terrible field name
    value: ApiResponse,
}

/// Represents a single joke provided by the ICNDB. The `id` field
/// uniquely identifies this specific joke, which allows the user
/// to get this joke again at a later time if he or she so desires.
#[derive(RustcDecodable, RustcEncodable)]
pub struct ApiResponse {
    pub id: u64,
    pub joke: String,
    pub categories: Box<[String]>
}

/// Returns an option value containing a random joke from the API
/// or, failing that, None.
pub fn next() -> Option<ApiResponse> {
    unwrap_response(execute_request("http://api.icndb.com/jokes/random"))
}

/// Returns an option value containing a random joke from the API
/// using the names supplied to the function instead of the default
/// name (Chuck Norris) or, failing that, None.
pub fn next_with_names(first: &str, last: &str) -> Option<ApiResponse> {
    unwrap_response(execute_request(&format!("http://api.icndb.com/jokes/random?firstName={}&lastName={}", first, last)))
}

/// Returns an option value containing a specified joke from the API
/// or, failing that, None.
pub fn get_by_id(id: u64) -> Option<ApiResponse> {
    unwrap_response(execute_request(&format!("http://api.icndb.com/jokes/{}", id)))
}

/// Returns an option value containing a specified joke from the API
/// using the names supplied to the function instead of the default
/// name (Chuck Norris) or, failing that, None.
pub fn get_by_id_with_names(id: u64, first: &str, last: &str) -> Option<ApiResponse> {
    unwrap_response(
        execute_request(
            &format!(
                "http://api.icndb.com/jokes/{}?firstName={}&lastName={}",
                id,
                first,
                last)))
}

/// Parses the response returned by a query against the ICNDB API
/// into an ApiResponse or, failing that, None.
fn unwrap_response(response: Option<String>) -> Option<ApiResponse> {
    let raw_response = match response {
        Some(response) => response,
        None => return None,
    };

    match json::decode::<ApiResponseWrapper>(&raw_response) {
        Ok(result) => unescape_content(result.value),
        _ => None
    }
}

/// Unescape HTML entities found in joke contents.
///
/// The ICNDB represents some values as HTML entities in the json
/// packets returned to the caller and rustc_deserialize does not
/// unescape these entities upon deserializing the json packet.
/// This function deals with that by taking the (potentially) escaped
/// values and unescaping any HTML entities contained therein before
/// returning a new ApiResponse struct containing the unescaped
/// values.
///
/// ** Entities handled include: **
/// - "
///
/// Hopefully we won't discover anymore.
fn unescape_content(response: ApiResponse) -> Option<ApiResponse> {
    if response.joke.contains(""") {
        Some(ApiResponse {
            id: response.id,
            joke: response.joke.replace(""", "\""),
            categories: response.categories
        })
    } else {
        Some(response)
    }
}

/// Executes an arbitrary request against the ICNDB API.
fn execute_request(request: &str) -> Option<String> {
    let mut client = Client::new();
    let mut response = match client.get(request).send() {
        Ok(res) => res,
        _ => return None
    };

    let mut content = String::new();
    match response.read_to_string(&mut content) {
       Ok(()) => Some(content),
        _ => None
    }
}
<|endoftext|>


<commit_before>//! A generic connection pool.
//!
//! Opening a new database connection every time one is needed is both
//! inefficient and can lead to resource exhaustion under high traffic
//! conditions. A connection pool maintains a set of open connections to a
//! database, handing them out for repeated use.
//!
//! r2d2 is agnostic to the connection type it is managing. Implementors of the
//! `ManageConnection` trait provide the database-specific logic to create and
//! check the health of connections.
//!
//! # Example
//!
//! Using an imaginary "foodb" database.
//!
//! ```rust,ignore
//! use std::thread;
//!
//! extern crate r2d2;
//! extern crate r2d2_foodb;
//!
//! fn main() {
//!     let config = r2d2::Config::builder()
//!         .pool_size(15)
//!         .error_handler(Box::new(r2d2::LoggingErrorHandler))
//!         .build();
//!     let manager = r2d2_foodb::FooConnectionManager::new("localhost:1234");
//!
//!     let pool = r2d2::Pool::new(config, manager).unwrap();
//!
//!     for _ in 0..20 {
//!         let pool = pool.clone();
//!         thread::spawn(move || {
//!             let conn = pool.get().unwrap();
//!             // use the connection
//!             // it will be returned to the pool when it falls out of scope.
//!         })
//!     }
//! }
//! ```
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/r2d2/doc/v0.6.2")]

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

use std::cmp;
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::sync::{Arc, Mutex, Condvar};
use time::{Duration, SteadyTime};

#[doc(inline)]
pub use config::Config;

use task::ScheduledThreadPool;

pub mod config;
mod task;
mod thunk;

#[cfg(test)]
mod test;

/// A trait which provides connection-specific functionality.
pub trait ManageConnection: Send + Sync + 'static {
    /// The connection type this manager deals with.
    type Connection: Send + 'static;

    /// The error type returned by `Connection`s.
    type Error: 'static;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ManageConnection`.
pub trait HandleError<E>: Send+Sync+'static {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// A `HandleError` implementation which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopErrorHandler;

impl<E> HandleError<E> for NopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// A `HandleError` implementation which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> HandleError<E> for LoggingErrorHandler where E: Error
{
    fn handle_error(&self, error: E) {
        error!("{}", error);
    }
}

/// A trait which allows for customization of connections.
pub trait CustomizeConnection<C, E>: Send+Sync+'static {
    /// Called with connections immediately after they are returned from
    /// `ManageConnection::connect`.
    ///
    /// The default implementation simply returns `Ok(())`.
    ///
    /// # Errors
    ///
    /// If this method returns an error, the connection will be discarded.
    #[allow(unused_variables)]
    fn on_acquire(&self, conn: &mut C) -> Result<(), E> {
        Ok(())
    }
}

/// A `CustomizeConnection` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopConnectionCustomizer;

impl<C, E> CustomizeConnection<C, E> for NopConnectionCustomizer {}

struct Conn<C> {
    conn: C,
    birth: SteadyTime,
    idle_start: SteadyTime,
}

impl<C> Conn<C> {
    fn new(conn: C) -> Conn<C> {
        let now = SteadyTime::now();
        Conn {
            conn: conn,
            birth: now,
            idle_start: now,
        }
    }
}

struct PoolInternals<C> {
    conns: VecDeque<Conn<C>>,
    num_conns: u32,
    pending_conns: u32,
}

struct SharedPool<M>
    where M: ManageConnection
{
    config: Config<M::Connection, M::Error>,
    manager: M,
    internals: Mutex<PoolInternals<M::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

impl<M> Drop for SharedPool<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.thread_pool.clear();
    }
}

fn drop_conn<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.num_conns -= 1;

    let min = shared.config.min_idle().unwrap_or(shared.config.pool_size());
    if internals.num_conns + internals.pending_conns < min {
        add_connection(shared, internals);
    }
}

fn add_connection<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.pending_conns += 1;
    inner(Duration::zero(), shared);

    fn inner<M>(delay: Duration, shared: &Arc<SharedPool<M>>)
        where M: ManageConnection
    {
        let new_shared = shared.clone();
        shared.thread_pool.run_after(delay, move || {
            let shared = new_shared;
            let conn = shared.manager.connect().and_then(|mut conn| {
                shared.config.connection_customizer().on_acquire(&mut conn).map(|_| conn)
            });
            match conn {
                Ok(conn) => {
                    let mut internals = shared.internals.lock().unwrap();
                    internals.conns.push_back(Conn::new(conn));
                    internals.pending_conns -= 1;
                    internals.num_conns += 1;
                    shared.cond.notify_one();
                }
                Err(err) => {
                    shared.config.error_handler().handle_error(err);
                    let delay = cmp::max(Duration::milliseconds(200), delay);
                    let delay = cmp::min(cvt(shared.config.connection_timeout()) / 2, delay * 2);
                    inner(delay, &shared);
                }
            }
        });
    }
}

fn reap_connections<M>(shared: &Arc<SharedPool<M>>)
    where M: ManageConnection
{
    let mut old = VecDeque::with_capacity(shared.config.pool_size() as usize);
    let mut to_drop = vec![];

    let mut internals = shared.internals.lock().unwrap();
    mem::swap(&mut old, &mut internals.conns);
    let now = SteadyTime::now();
    for conn in old {
        let mut reap = false;
        if let Some(timeout) = shared.config.idle_timeout() {
            reap |= now - conn.idle_start >= cvt(timeout);
        }
        if let Some(lifetime) = shared.config.max_lifetime() {
            reap |= now - conn.birth >= cvt(lifetime);
        }
        if reap {
            drop_conn(shared, &mut internals);
            to_drop.push(conn.conn);
        } else {
            internals.conns.push_back(conn);
        }
    }
    drop(internals); // make sure we run to_drop destructors without this locked
}

/// A generic connection pool.
pub struct Pool<M>
    where M: ManageConnection
{
    shared: Arc<SharedPool<M>>,
}

/// Returns a new `Pool` referencing the same state as `self`.
impl<M> Clone for Pool<M> where M: ManageConnection
{
    fn clone(&self) -> Pool<M> {
        Pool { shared: self.shared.clone() }
    }
}

impl<M> fmt::Debug for Pool<M> where M: ManageConnection + fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let inner = self.shared.internals.lock().unwrap();

        fmt.debug_struct("Pool")
           .field("connections", &inner.num_conns)
           .field("idle_connections", &inner.conns.len())
           .field("config", &self.shared.config)
           .field("manager", &self.shared.manager)
           .finish()
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError(());

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout(());

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ManageConnection
{
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    pub fn new(config: Config<M::Connection, M::Error>,
               manager: M)
               -> Result<Pool<M>, InitializationError> {
        Pool::new_inner(config, manager, 30)
    }

    // for testing
    fn new_inner(config: Config<M::Connection, M::Error>,
                 manager: M,
                 reaper_rate: i64)
                 -> Result<Pool<M>, InitializationError> {
        let internals = PoolInternals {
            conns: VecDeque::with_capacity(config.pool_size() as usize),
            num_conns: 0,
            pending_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            thread_pool: ScheduledThreadPool::new(config.helper_threads() as usize),
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        let initial_size = shared.config.min_idle().unwrap_or(shared.config.pool_size());
        {
            let mut inner = shared.internals.lock().unwrap();
            for _ in 0..initial_size {
                add_connection(&shared, &mut inner);
            }
            drop(inner);
        }

        if shared.config.initialization_fail_fast() {
            let end = SteadyTime::now() + cvt(shared.config.connection_timeout());
            let mut internals = shared.internals.lock().unwrap();

            while internals.num_conns != initial_size {
                let wait = end - SteadyTime::now();
                if wait <= Duration::zero() {
                    return Err(InitializationError(()));
                }
                internals = shared.cond
                                  .wait_timeout_ms(internals, wait.num_milliseconds() as u32)
                                  .unwrap()
                                  .0;
            }
        }

        if shared.config.max_lifetime().is_some() || shared.config.idle_timeout().is_some() {
            let s = shared.clone();
            shared.thread_pool
                  .run_at_fixed_rate(Duration::seconds(reaper_rate), move || reap_connections(&s));
        }

        Ok(Pool { shared: shared })
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get(&self) -> Result<PooledConnection<M>, GetTimeout> {
        let end = SteadyTime::now() + cvt(self.shared.config.connection_timeout());
        let mut internals = self.shared.internals.lock().unwrap();

        let connection;
        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out() {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn.conn) {
                            self.shared.config.error_handler().handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            drop_conn(&self.shared, &mut internals);
                            continue;
                        }
                    }

                    connection = conn;
                    break;
                }
                None => {
                    if internals.num_conns + internals.pending_conns <
                       self.shared.config.pool_size() {
                        add_connection(&self.shared, &mut internals);
                    }

                    let now = SteadyTime::now();
                    let mut timeout = (end - now).num_milliseconds();
                    if timeout < 0 {
                        timeout = 0
                    };
                    let (new_internals, no_timeout) = self.shared
                                                          .cond
                                                          .wait_timeout_ms(internals,
                                                                           timeout as u32)
                                                          .unwrap();
                    internals = new_internals;

                    if !no_timeout {
                        return Err(GetTimeout(()));
                    }
                }
            }
        }

        Ok(PooledConnection {
            pool: self.clone(),
            conn: Some(connection),
        })
    }

    fn put_back(&self, mut conn: Conn<M::Connection>) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn.conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            drop_conn(&self.shared, &mut internals);
        } else {
            conn.idle_start = SteadyTime::now();
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M>
    where M: ManageConnection
{
    pool: Pool<M>,
    conn: Option<Conn<M::Connection>>,
}

impl<M> fmt::Debug for PooledConnection<M>
    where M: ManageConnection,
          M::Connection: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.conn.as_ref().unwrap().conn, fmt)
    }
}

impl<M> Drop for PooledConnection<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M> where M: ManageConnection
{
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        &self.conn.as_ref().unwrap().conn
    }
}

impl<M> DerefMut for PooledConnection<M> where M: ManageConnection
{
    fn deref_mut(&mut self) -> &mut M::Connection {
        &mut self.conn.as_mut().unwrap().conn
    }
}

fn cvt(d: std::time::Duration) -> Duration {
    Duration::seconds(d.as_secs() as i64) + Duration::nanoseconds(d.subsec_nanos() as i64)
}
<commit_msg>Clean up wait logic<commit_after>//! A generic connection pool.
//!
//! Opening a new database connection every time one is needed is both
//! inefficient and can lead to resource exhaustion under high traffic
//! conditions. A connection pool maintains a set of open connections to a
//! database, handing them out for repeated use.
//!
//! r2d2 is agnostic to the connection type it is managing. Implementors of the
//! `ManageConnection` trait provide the database-specific logic to create and
//! check the health of connections.
//!
//! # Example
//!
//! Using an imaginary "foodb" database.
//!
//! ```rust,ignore
//! use std::thread;
//!
//! extern crate r2d2;
//! extern crate r2d2_foodb;
//!
//! fn main() {
//!     let config = r2d2::Config::builder()
//!         .pool_size(15)
//!         .error_handler(Box::new(r2d2::LoggingErrorHandler))
//!         .build();
//!     let manager = r2d2_foodb::FooConnectionManager::new("localhost:1234");
//!
//!     let pool = r2d2::Pool::new(config, manager).unwrap();
//!
//!     for _ in 0..20 {
//!         let pool = pool.clone();
//!         thread::spawn(move || {
//!             let conn = pool.get().unwrap();
//!             // use the connection
//!             // it will be returned to the pool when it falls out of scope.
//!         })
//!     }
//! }
//! ```
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/r2d2/doc/v0.6.2")]

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

use std::cmp;
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::sync::{Arc, Mutex, Condvar};
use time::{Duration, SteadyTime};

#[doc(inline)]
pub use config::Config;

use task::ScheduledThreadPool;

pub mod config;
mod task;
mod thunk;

#[cfg(test)]
mod test;

/// A trait which provides connection-specific functionality.
pub trait ManageConnection: Send + Sync + 'static {
    /// The connection type this manager deals with.
    type Connection: Send + 'static;

    /// The error type returned by `Connection`s.
    type Error: 'static;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ManageConnection`.
pub trait HandleError<E>: Send+Sync+'static {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// A `HandleError` implementation which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopErrorHandler;

impl<E> HandleError<E> for NopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// A `HandleError` implementation which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> HandleError<E> for LoggingErrorHandler where E: Error
{
    fn handle_error(&self, error: E) {
        error!("{}", error);
    }
}

/// A trait which allows for customization of connections.
pub trait CustomizeConnection<C, E>: Send+Sync+'static {
    /// Called with connections immediately after they are returned from
    /// `ManageConnection::connect`.
    ///
    /// The default implementation simply returns `Ok(())`.
    ///
    /// # Errors
    ///
    /// If this method returns an error, the connection will be discarded.
    #[allow(unused_variables)]
    fn on_acquire(&self, conn: &mut C) -> Result<(), E> {
        Ok(())
    }
}

/// A `CustomizeConnection` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopConnectionCustomizer;

impl<C, E> CustomizeConnection<C, E> for NopConnectionCustomizer {}

struct Conn<C> {
    conn: C,
    birth: SteadyTime,
    idle_start: SteadyTime,
}

impl<C> Conn<C> {
    fn new(conn: C) -> Conn<C> {
        let now = SteadyTime::now();
        Conn {
            conn: conn,
            birth: now,
            idle_start: now,
        }
    }
}

struct PoolInternals<C> {
    conns: VecDeque<Conn<C>>,
    num_conns: u32,
    pending_conns: u32,
}

struct SharedPool<M>
    where M: ManageConnection
{
    config: Config<M::Connection, M::Error>,
    manager: M,
    internals: Mutex<PoolInternals<M::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

impl<M> Drop for SharedPool<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.thread_pool.clear();
    }
}

fn drop_conn<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.num_conns -= 1;

    let min = shared.config.min_idle().unwrap_or(shared.config.pool_size());
    if internals.num_conns + internals.pending_conns < min {
        add_connection(shared, internals);
    }
}

fn add_connection<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.pending_conns += 1;
    inner(Duration::zero(), shared);

    fn inner<M>(delay: Duration, shared: &Arc<SharedPool<M>>)
        where M: ManageConnection
    {
        let new_shared = shared.clone();
        shared.thread_pool.run_after(delay, move || {
            let shared = new_shared;
            let conn = shared.manager.connect().and_then(|mut conn| {
                shared.config.connection_customizer().on_acquire(&mut conn).map(|_| conn)
            });
            match conn {
                Ok(conn) => {
                    let mut internals = shared.internals.lock().unwrap();
                    internals.conns.push_back(Conn::new(conn));
                    internals.pending_conns -= 1;
                    internals.num_conns += 1;
                    shared.cond.notify_one();
                }
                Err(err) => {
                    shared.config.error_handler().handle_error(err);
                    let delay = cmp::max(Duration::milliseconds(200), delay);
                    let delay = cmp::min(cvt(shared.config.connection_timeout()) / 2, delay * 2);
                    inner(delay, &shared);
                }
            }
        });
    }
}

fn reap_connections<M>(shared: &Arc<SharedPool<M>>)
    where M: ManageConnection
{
    let mut old = VecDeque::with_capacity(shared.config.pool_size() as usize);
    let mut to_drop = vec![];

    let mut internals = shared.internals.lock().unwrap();
    mem::swap(&mut old, &mut internals.conns);
    let now = SteadyTime::now();
    for conn in old {
        let mut reap = false;
        if let Some(timeout) = shared.config.idle_timeout() {
            reap |= now - conn.idle_start >= cvt(timeout);
        }
        if let Some(lifetime) = shared.config.max_lifetime() {
            reap |= now - conn.birth >= cvt(lifetime);
        }
        if reap {
            drop_conn(shared, &mut internals);
            to_drop.push(conn.conn);
        } else {
            internals.conns.push_back(conn);
        }
    }
    drop(internals); // make sure we run to_drop destructors without this locked
}

/// A generic connection pool.
pub struct Pool<M>
    where M: ManageConnection
{
    shared: Arc<SharedPool<M>>,
}

/// Returns a new `Pool` referencing the same state as `self`.
impl<M> Clone for Pool<M> where M: ManageConnection
{
    fn clone(&self) -> Pool<M> {
        Pool { shared: self.shared.clone() }
    }
}

impl<M> fmt::Debug for Pool<M> where M: ManageConnection + fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let inner = self.shared.internals.lock().unwrap();

        fmt.debug_struct("Pool")
           .field("connections", &inner.num_conns)
           .field("idle_connections", &inner.conns.len())
           .field("config", &self.shared.config)
           .field("manager", &self.shared.manager)
           .finish()
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError(());

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout(());

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ManageConnection
{
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    pub fn new(config: Config<M::Connection, M::Error>,
               manager: M)
               -> Result<Pool<M>, InitializationError> {
        Pool::new_inner(config, manager, 30)
    }

    // for testing
    fn new_inner(config: Config<M::Connection, M::Error>,
                 manager: M,
                 reaper_rate: i64)
                 -> Result<Pool<M>, InitializationError> {
        let internals = PoolInternals {
            conns: VecDeque::with_capacity(config.pool_size() as usize),
            num_conns: 0,
            pending_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            thread_pool: ScheduledThreadPool::new(config.helper_threads() as usize),
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        let initial_size = shared.config.min_idle().unwrap_or(shared.config.pool_size());
        {
            let mut inner = shared.internals.lock().unwrap();
            for _ in 0..initial_size {
                add_connection(&shared, &mut inner);
            }
            drop(inner);
        }

        if shared.config.initialization_fail_fast() {
            let end = SteadyTime::now() + cvt(shared.config.connection_timeout());
            let mut internals = shared.internals.lock().unwrap();

            while internals.num_conns != initial_size {
                let wait = end - SteadyTime::now();
                if wait <= Duration::zero() {
                    return Err(InitializationError(()));
                }
                internals = shared.cond
                                  .wait_timeout_ms(internals, wait.num_milliseconds() as u32)
                                  .unwrap()
                                  .0;
            }
        }

        if shared.config.max_lifetime().is_some() || shared.config.idle_timeout().is_some() {
            let s = shared.clone();
            shared.thread_pool
                  .run_at_fixed_rate(Duration::seconds(reaper_rate), move || reap_connections(&s));
        }

        Ok(Pool { shared: shared })
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get(&self) -> Result<PooledConnection<M>, GetTimeout> {
        let end = SteadyTime::now() + cvt(self.shared.config.connection_timeout());
        let mut internals = self.shared.internals.lock().unwrap();

        let connection;
        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out() {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn.conn) {
                            self.shared.config.error_handler().handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            drop_conn(&self.shared, &mut internals);
                            continue;
                        }
                    }

                    connection = conn;
                    break;
                }
                None => {
                    if internals.num_conns + internals.pending_conns <
                       self.shared.config.pool_size() {
                        add_connection(&self.shared, &mut internals);
                    }

                    let now = SteadyTime::now();
                    let timeout = (end - now).num_milliseconds();
                    if timeout <= 0 {
                        return Err(GetTimeout(()));
                    };
                    internals = self.shared
                                    .cond
                                    .wait_timeout_ms(internals, timeout as u32)
                                    .unwrap()
                                    .0;
                }
            }
        }

        Ok(PooledConnection {
            pool: self.clone(),
            conn: Some(connection),
        })
    }

    fn put_back(&self, mut conn: Conn<M::Connection>) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn.conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            drop_conn(&self.shared, &mut internals);
        } else {
            conn.idle_start = SteadyTime::now();
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M>
    where M: ManageConnection
{
    pool: Pool<M>,
    conn: Option<Conn<M::Connection>>,
}

impl<M> fmt::Debug for PooledConnection<M>
    where M: ManageConnection,
          M::Connection: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.conn.as_ref().unwrap().conn, fmt)
    }
}

impl<M> Drop for PooledConnection<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M> where M: ManageConnection
{
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        &self.conn.as_ref().unwrap().conn
    }
}

impl<M> DerefMut for PooledConnection<M> where M: ManageConnection
{
    fn deref_mut(&mut self) -> &mut M::Connection {
        &mut self.conn.as_mut().unwrap().conn
    }
}

fn cvt(d: std::time::Duration) -> Duration {
    Duration::seconds(d.as_secs() as i64) + Duration::nanoseconds(d.subsec_nanos() as i64)
}
<|endoftext|>


<commit_before>//! This is documentation for the `changes-stream` crate.
//!
//! The `changes-stream` crate is designed to give you a readable stream of
//! chunked data, upon which you can register multiple handlers, that are
//! called on Read of the data chunk.

extern crate futures;
extern crate hyper;
extern crate tokio_core;

use futures::Future;
use futures::stream::Stream;

use hyper::Client;

type Event = hyper::Chunk;

/// A structure to generate a readable stream on which you can register handlers.
///
/// Internally, the `ChangesStream` struct holds 3 members:
///
/// | Member      | Type                                  | Notes                                                                   |
/// |-------------|---------------------------------------|-------------------------------------------------------------------------|
/// | `db`        | `String`                              | A url pointing to the data you'd like to stream.                        |
/// | `lp`        | [`tokio_core::reactor::Core`]         | The event loop                                                          |
/// | `handlers`  | `Vec<F> where F: Fn(&`[`hyper::Chunk`]`)` | A vector of handlers to be called on each Chunk from the Stream on Read |
///
/// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
/// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
pub struct ChangesStream {
    db: hyper::Url,
    lp: tokio_core::reactor::Core,
    handlers: Vec<Box<Fn(&Event)>>,
}

impl ChangesStream {

    /// Constructs a new `ChangesStream` struct
    ///
    /// Takes a single argument, `db`, which represents the
    /// url of the data you wish to stream.
    ///
    /// Every `ChangesStream` struct is initialized with
    /// an event loop ([`tokio_core::reactor::Core`]) and an
    /// empty vector of handlers. See above for more details.
    ///
    /// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
    ///
    /// For example, to create a new `ChangesStream` struct
    /// for the npmjs registry, you would write:
    ///
    /// ```no_run
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use std::io;
    /// # use std::io::Write;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    ///     let url = "https://replicate.npmjs.com/_changes".to_string();
    ///     let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       io::stdout().write_all(&change).unwrap();
    /// #   });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn new(db: String) -> ChangesStream {
        ChangesStream {
            db: db.parse().unwrap(),
            lp: tokio_core::reactor::Core::new().unwrap(),
            handlers: vec![],
        }
    }

    /// Registers a handler. A handler is simply a function
    /// you'd like to call on a chunk from the stream at the
    /// time the chunk is read.
    ///
    /// `.on()` takes a single argument, a closure. The
    /// closure you pass should take a single [`hyper::Chunk`]
    /// as an argument.
    ///
    /// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
    ///
    /// For example, to write the data in a chunk to standard
    /// out, you would write:
    ///
    /// ```no_run
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use std::io;
    /// # use std::io::Write;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    ///    changes.on(|change| {
    ///        io::stdout().write_all(&change).unwrap();
    ///    });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn on<F: Fn(&Event) + 'static>(&mut self, handler: F) {
        self.handlers.push(Box::new(handler));
    }

    /// Runs the `ChangesStream` struct's event loop, `lp`.
    ///
    /// Call this after you have regsitered all handlers using
    /// `on`.
    ///
    /// Takes no arguments.
    ///
    /// For example:
    ///
    /// ```no_run
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use std::io;
    /// # use std::io::Write;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       io::stdout().write_all(&change).unwrap();
    /// #   });
    /// #
    ///    changes.run();
    /// # }
    /// ```
    pub fn run(mut self) {
        let client = Client::new(&self.lp.handle()).unwrap();

        let handlers = self.handlers;
        self.lp
            .run(client.get(self.db).and_then(move |res| {
                assert!(res.status().is_success());

                res.body().for_each(move |chunk| {
                    for handler in &handlers {
                        // let event = serde_json::decode(chunk);
                        handler(&chunk);
                    }
                    Ok(())
                })
            }))
            .unwrap();

    }
}
<commit_msg>make hyper::client mut per hyper update<commit_after>//! This is documentation for the `changes-stream` crate.
//!
//! The `changes-stream` crate is designed to give you a readable stream of
//! chunked data, upon which you can register multiple handlers, that are
//! called on Read of the data chunk.

extern crate futures;
extern crate hyper;
extern crate tokio_core;

use futures::Future;
use futures::stream::Stream;

use hyper::Client;

type Event = hyper::Chunk;

/// A structure to generate a readable stream on which you can register handlers.
///
/// Internally, the `ChangesStream` struct holds 3 members:
///
/// | Member      | Type                                  | Notes                                                                   |
/// |-------------|---------------------------------------|-------------------------------------------------------------------------|
/// | `db`        | `String`                              | A url pointing to the data you'd like to stream.                        |
/// | `lp`        | [`tokio_core::reactor::Core`]         | The event loop                                                          |
/// | `handlers`  | `Vec<F> where F: Fn(&`[`hyper::Chunk`]`)` | A vector of handlers to be called on each Chunk from the Stream on Read |
///
/// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
/// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
pub struct ChangesStream {
    db: hyper::Url,
    lp: tokio_core::reactor::Core,
    handlers: Vec<Box<Fn(&Event)>>,
}

impl ChangesStream {

    /// Constructs a new `ChangesStream` struct
    ///
    /// Takes a single argument, `db`, which represents the
    /// url of the data you wish to stream.
    ///
    /// Every `ChangesStream` struct is initialized with
    /// an event loop ([`tokio_core::reactor::Core`]) and an
    /// empty vector of handlers. See above for more details.
    ///
    /// [`tokio_core::reactor::Core`]: ../tokio_core/reactor/struct.Core.html
    ///
    /// For example, to create a new `ChangesStream` struct
    /// for the npmjs registry, you would write:
    ///
    /// ```no_run
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use std::io;
    /// # use std::io::Write;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    ///     let url = "https://replicate.npmjs.com/_changes".to_string();
    ///     let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       io::stdout().write_all(&change).unwrap();
    /// #   });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn new(db: String) -> ChangesStream {
        ChangesStream {
            db: db.parse().unwrap(),
            lp: tokio_core::reactor::Core::new().unwrap(),
            handlers: vec![],
        }
    }

    /// Registers a handler. A handler is simply a function
    /// you'd like to call on a chunk from the stream at the
    /// time the chunk is read.
    ///
    /// `.on()` takes a single argument, a closure. The
    /// closure you pass should take a single [`hyper::Chunk`]
    /// as an argument.
    ///
    /// [`hyper::Chunk`]: ../hyper/struct.Chunk.html
    ///
    /// For example, to write the data in a chunk to standard
    /// out, you would write:
    ///
    /// ```no_run
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use std::io;
    /// # use std::io::Write;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    ///    changes.on(|change| {
    ///        io::stdout().write_all(&change).unwrap();
    ///    });
    /// #
    /// #   changes.run();
    /// # }
    /// ```
    pub fn on<F: Fn(&Event) + 'static>(&mut self, handler: F) {
        self.handlers.push(Box::new(handler));
    }

    /// Runs the `ChangesStream` struct's event loop, `lp`.
    ///
    /// Call this after you have regsitered all handlers using
    /// `on`.
    ///
    /// Takes no arguments.
    ///
    /// For example:
    ///
    /// ```no_run
    /// # extern crate changes_stream;
    /// # extern crate futures;
    /// #
    /// # use std::io;
    /// # use std::io::Write;
    /// #
    /// # use changes_stream::ChangesStream;
    /// #
    /// # fn main() {
    /// #   let url = "https://replicate.npmjs.com/_changes".to_string();
    /// #   let mut changes = ChangesStream::new(url);
    /// #
    /// #   changes.on(|change| {
    /// #       io::stdout().write_all(&change).unwrap();
    /// #   });
    /// #
    ///    changes.run();
    /// # }
    /// ```
    pub fn run(mut self) {
        let mut client = Client::new(&self.lp.handle()).unwrap();

        let handlers = self.handlers;
        self.lp
            .run(client.get(self.db).and_then(move |res| {
                assert!(res.status().is_success());

                res.body().for_each(move |chunk| {
                    for handler in &handlers {
                        // let event = serde_json::decode(chunk);
                        handler(&chunk);
                    }
                    Ok(())
                })
            }))
            .unwrap();

    }
}
<|endoftext|>