<commit_before>#[link(name="base64", vers="1.0.0", author="Jordy Dickinson")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern mod extra;

use std::char;
use std::io::{File, stdin, stdout};
use std::os;
use std::str;

use extra::base64;
use extra::base64::{FromBase64, ToBase64};

fn main() {
    let mut conf = Conf::new(os::args());

    match conf.mode {
        Decode  => decode(&mut conf),
        Encode  => encode(&mut conf),
        Help    => help(&conf),
        Version => version()
    }
}

fn decode(conf: &mut Conf) {
    let mut to_decode = str::from_utf8_owned(conf.input_file.read_to_end());

    to_decode = to_decode.replace("\n", "");

    if conf.ignore_garbage {
        let standard_chars =
            bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
                   "abcdefghijklmnopqrstuvwxyz",
                   "0123456789+/").map(|b| char::from_u32(*b as u32).unwrap());

        to_decode = to_decode
            .trim_chars(&|c| !standard_chars.contains(&c))
            .to_owned();
    }

    match to_decode.from_base64() {
        Ok(bytes) => {
            let mut out = stdout();

            out.write(bytes);
            out.flush();
        }
        Err(s) => {
            error!("error: {:s}", s);
            fail!()
        }
    }
}

fn encode(conf: &mut Conf) {
    let b64_conf = base64::Config {
        char_set: base64::Standard,
        pad: true,
        line_length: match conf.line_wrap {
            0 => None,
            _ => Some(conf.line_wrap)
        }
    };
    let to_encode = conf.input_file.read_to_end();
    let mut encoded = to_encode.to_base64(b64_conf);

    // To my knowledge, RFC 3548 does not specify which line endings to use. It
    // seems that rust's base64 algorithm uses CRLF as prescribed by RFC 2045.
    // However, since GNU base64 outputs only LF (presumably because that is
    // the standard UNIX line ending), we strip CRs from the output to maintain
    // compatibility.
    encoded = encoded.replace("\r", "");

    println(encoded);
}

fn help(conf: &Conf) {
    println!("Usage: {:s} [OPTION]... [FILE]", conf.progname);
    println("");
    println(conf.usage);

    let msg = ~"With no FILE, or when FILE is -, read standard input.\n\n"
        + "The data are encoded as described for the base64 alphabet in RFC "
        + "3548. When\ndecoding, the input may contain newlines in addition "
        + "to the bytes of the formal\nbase64 alphabet. Use --ignore-garbage "
        + "to attempt to recover from any other\nnon-alphabet bytes in the "
        + "encoded stream.";

    println(msg);
}

fn version() {
    println("base64 1.0.0");
}

struct Conf {
    progname: ~str,
    usage: ~str,
    mode: Mode,
    ignore_garbage: bool,
    line_wrap: uint,
    input_file: ~Reader
}

impl Conf {
    fn new(args: &[~str]) -> Conf {
        // The use statement is here rather than at the top of the file so that
        // the reader is made directly aware that we're using getopts::groups,
        // and not just getopts. Also some names are somewhat vague taken out
        // of context (i.e., "usage").
        use extra::getopts::groups::{
            getopts,
            optflag,
            optopt,
            usage
        };

        let opts = ~[
            optflag("d", "decode", "decode data"),
            optflag("i", "ignore-garbage",
            "when decoding, ignore non-alphabetic characters"),
            optopt("w", "wrap",
            "wrap encoded lines after COLS character (default 76, 0 to disable"
            + " wrapping)", "COLS"),
            optflag("h", "help", "display this help text and exit"),
            optflag("V", "version", "output version information and exit")
        ];
        let matches = match getopts(args.tail(), opts) {
            Ok(m) => m,
            Err(e) => {
                error!("error: {:s}", e.to_err_msg());
                fail!()
            }
        };

        Conf {
            progname: args[0].clone(),
            usage: usage("Base64 encode or decode FILE, or standard input, to "
                         + "standard output.", opts),
            mode: if matches.opt_present("help") {
                Help
            } else if matches.opt_present("version") {
                Version
            } else if matches.opt_present("decode") {
                Decode
            } else {
                Encode
            },
            ignore_garbage: matches.opt_present("ignore-garbage"),
            line_wrap: match matches.opt_str("wrap") {
                Some(s) => match from_str(s) {
                    Some(s) => s,
                    None => {
                        error!("error: {:s}",
                               "Argument to option 'wrap' improperly "
                               + "formatted.");
                        fail!()
                    }
                },
                None => 76
            },
            input_file: if matches.free.is_empty()
                            || matches.free[0] == ~"-" {
                ~stdin() as ~Reader
            } else {
                let path = Path::new(matches.free[0]);
                ~File::open(&path) as ~Reader
            }
        }
    }
}

enum Mode {
    Decode,
    Encode,
    Help,
    Version
}

<commit_msg>Use line continuations instead of string addition<commit_after>#[link(name="base64", vers="1.0.0", author="Jordy Dickinson")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern mod extra;

use std::char;
use std::io::{File, stdin, stdout};
use std::os;
use std::str;

use extra::base64;
use extra::base64::{FromBase64, ToBase64};

fn main() {
    let mut conf = Conf::new(os::args());

    match conf.mode {
        Decode  => decode(&mut conf),
        Encode  => encode(&mut conf),
        Help    => help(&conf),
        Version => version()
    }
}

fn decode(conf: &mut Conf) {
    let mut to_decode = str::from_utf8_owned(conf.input_file.read_to_end());

    to_decode = to_decode.replace("\n", "");

    if conf.ignore_garbage {
        let standard_chars =
            bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
            "abcdefghijklmnopqrstuvwxyz",
            "0123456789+/").map(|b| char::from_u32(*b as u32).unwrap());

        to_decode = to_decode
            .trim_chars(&|c| !standard_chars.contains(&c))
            .to_owned();
    }

    match to_decode.from_base64() {
        Ok(bytes) => {
            let mut out = stdout();

            out.write(bytes);
            out.flush();
        }
        Err(s) => {
            error!("error: {:s}", s);
            fail!()
        }
    }
}

fn encode(conf: &mut Conf) {
    let b64_conf = base64::Config {
        char_set: base64::Standard,
        pad: true,
        line_length: match conf.line_wrap {
            0 => None,
            _ => Some(conf.line_wrap)
        }
    };
    let to_encode = conf.input_file.read_to_end();
    let mut encoded = to_encode.to_base64(b64_conf);

    // To my knowledge, RFC 3548 does not specify which line endings to use. It
    // seems that rust's base64 algorithm uses CRLF as prescribed by RFC 2045.
    // However, since GNU base64 outputs only LF (presumably because that is
    // the standard UNIX line ending), we strip CRs from the output to maintain
    // compatibility.
    encoded = encoded.replace("\r", "");

    println(encoded);
}

fn help(conf: &Conf) {
    println!("Usage: {:s} [OPTION]... [FILE]", conf.progname);
    println("");
    println(conf.usage);

    let msg = ~"With no FILE, or when FILE is -, read standard input.\n\n\
        The data are encoded as described for the base64 alphabet in RFC \
        3548. When\ndecoding, the input may contain newlines in addition \
        to the bytes of the formal\nbase64 alphabet. Use --ignore-garbage \
        to attempt to recover from any other\nnon-alphabet bytes in the \
        encoded stream.";

    println(msg);
}

fn version() {
    println("base64 1.0.0");
}

struct Conf {
    progname: ~str,
    usage: ~str,
    mode: Mode,
    ignore_garbage: bool,
    line_wrap: uint,
    input_file: ~Reader
}

impl Conf {
    fn new(args: &[~str]) -> Conf {
        // The use statement is here rather than at the top of the file so that
        // the reader is made directly aware that we're using getopts::groups,
        // and not just getopts. Also some names are somewhat vague taken out
        // of context (i.e., "usage").
        use extra::getopts::groups::{
            getopts,
            optflag,
            optopt,
            usage
        };

        let opts = ~[
            optflag("d", "decode", "decode data"),
            optflag("i", "ignore-garbage",
            "when decoding, ignore non-alphabetic characters"),
            optopt("w", "wrap",
            "wrap encoded lines after COLS character (default 76, 0 to \
            disable wrapping)", "COLS"),
            optflag("h", "help", "display this help text and exit"),
            optflag("V", "version", "output version information and exit")
                ];
        let matches = match getopts(args.tail(), opts) {
            Ok(m) => m,
            Err(e) => {
                error!("error: {:s}", e.to_err_msg());
                fail!()
            }
        };

        Conf {
            progname: args[0].clone(),
            usage: usage("Base64 encode or decode FILE, or standard input, to \
                         standard output.", opts),
            mode: if matches.opt_present("help") {
                Help
            } else if matches.opt_present("version") {
                Version
            } else if matches.opt_present("decode") {
                Decode
            } else {
                Encode
            },
            ignore_garbage: matches.opt_present("ignore-garbage"),
            line_wrap: match matches.opt_str("wrap") {
                Some(s) => match from_str(s) {
                    Some(s) => s,
                    None => {
                        error!("error: {:s}", "Argument to option 'wrap' \
                               improperly formatted.");
                        fail!()
                    }
                },
                None => 76
            },
            input_file: if matches.free.is_empty()
                            || matches.free[0] == ~"-" {
                ~stdin() as ~Reader
            } else {
                let path = Path::new(matches.free[0]);
                ~File::open(&path) as ~Reader
            }
        }
    }
}

enum Mode {
    Decode,
    Encode,
    Help,
    Version
}

<|endoftext|>


<commit_before>//! System bindings for HermitCore
//!
//! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for HermitCore.
//!
//! This is all super highly experimental and not actually intended for
//! wide/production use yet, it's still all in the experimental category. This
//! will likely change over time.
//!
//! Currently all functions here are basically stubs that immediately return
//! errors. The hope is that with a portability lint we can turn actually just
//! remove all this and just omit parts of the standard library if we're
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!

use crate::intrinsics;
use crate::os::raw::c_char;

pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
#[path = "../unsupported/process.rs"]
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;

use crate::io::ErrorKind;
pub use crate::sys_common::os_str_bytes as os_str;

#[allow(unused_extern_crates)]
pub extern crate hermit_abi as abi;

pub fn unsupported<T>() -> crate::io::Result<T> {
    Err(unsupported_err())
}

pub fn unsupported_err() -> crate::io::Error {
    crate::io::Error::new(crate::io::ErrorKind::Other, "operation not supported on HermitCore yet")
}

// This enum is used as the storage for a bunch of types which can't actually
// exist.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Void {}

pub unsafe fn strlen(start: *const c_char) -> usize {
    let mut str = start;

    while *str != 0 {
        str = str.offset(1);
    }

    (str as usize) - (start as usize)
}

#[no_mangle]
pub extern "C" fn floor(x: f64) -> f64 {
    unsafe { intrinsics::floorf64(x) }
}

pub fn abort_internal() -> ! {
    unsafe {
        abi::abort();
    }
}

// FIXME: just a workaround to test the system
pub fn hashmap_random_keys() -> (u64, u64) {
    (1, 2)
}

// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[no_mangle]
// NB. used by both libunwind and libpanic_abort
pub extern "C" fn __rust_abort() {
    abort_internal();
}

#[cfg(not(test))]
pub fn init() {
    let _ = net::init();
}

#[cfg(not(test))]
#[no_mangle]
pub unsafe extern "C" fn runtime_entry(
    argc: i32,
    argv: *const *const c_char,
    env: *const *const c_char,
) -> ! {
    use crate::sys::hermit::thread_local_dtor::run_dtors;
    extern "C" {
        fn main(argc: isize, argv: *const *const c_char) -> i32;
    }

    // initialize environment
    os::init_environment(env as *const *const i8);

    let result = main(argc as isize, argv);

    run_dtors();
    abi::exit(result);
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno {
        x if x == 13 as i32 => ErrorKind::PermissionDenied,
        x if x == 98 as i32 => ErrorKind::AddrInUse,
        x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
        x if x == 11 as i32 => ErrorKind::WouldBlock,
        x if x == 103 as i32 => ErrorKind::ConnectionAborted,
        x if x == 111 as i32 => ErrorKind::ConnectionRefused,
        x if x == 104 as i32 => ErrorKind::ConnectionReset,
        x if x == 17 as i32 => ErrorKind::AlreadyExists,
        x if x == 4 as i32 => ErrorKind::Interrupted,
        x if x == 22 as i32 => ErrorKind::InvalidInput,
        x if x == 2 as i32 => ErrorKind::NotFound,
        x if x == 107 as i32 => ErrorKind::NotConnected,
        x if x == 1 as i32 => ErrorKind::PermissionDenied,
        x if x == 32 as i32 => ErrorKind::BrokenPipe,
        x if x == 110 as i32 => ErrorKind::TimedOut,
        _ => ErrorKind::Other,
    }
}

pub fn cvt(result: i32) -> crate::io::Result<usize> {
    if result < 0 { Err(crate::io::Error::from_raw_os_error(-result)) } else { Ok(result as usize) }
}
<commit_msg>Rollup merge of #74979 - maekawatoshiki:fix, r=Mark-Simulacrum<commit_after>//! System bindings for HermitCore
//!
//! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for HermitCore.
//!
//! This is all super highly experimental and not actually intended for
//! wide/production use yet, it's still all in the experimental category. This
//! will likely change over time.
//!
//! Currently all functions here are basically stubs that immediately return
//! errors. The hope is that with a portability lint we can turn actually just
//! remove all this and just omit parts of the standard library if we're
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!

#![allow(unsafe_op_in_unsafe_fn)]

use crate::intrinsics;
use crate::os::raw::c_char;

pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
#[path = "../unsupported/process.rs"]
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;

use crate::io::ErrorKind;
pub use crate::sys_common::os_str_bytes as os_str;

#[allow(unused_extern_crates)]
pub extern crate hermit_abi as abi;

pub fn unsupported<T>() -> crate::io::Result<T> {
    Err(unsupported_err())
}

pub fn unsupported_err() -> crate::io::Error {
    crate::io::Error::new(crate::io::ErrorKind::Other, "operation not supported on HermitCore yet")
}

// This enum is used as the storage for a bunch of types which can't actually
// exist.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Void {}

pub unsafe fn strlen(start: *const c_char) -> usize {
    let mut str = start;

    while *str != 0 {
        str = str.offset(1);
    }

    (str as usize) - (start as usize)
}

#[no_mangle]
pub extern "C" fn floor(x: f64) -> f64 {
    unsafe { intrinsics::floorf64(x) }
}

pub fn abort_internal() -> ! {
    unsafe {
        abi::abort();
    }
}

// FIXME: just a workaround to test the system
pub fn hashmap_random_keys() -> (u64, u64) {
    (1, 2)
}

// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[no_mangle]
// NB. used by both libunwind and libpanic_abort
pub extern "C" fn __rust_abort() {
    abort_internal();
}

#[cfg(not(test))]
pub fn init() {
    let _ = net::init();
}

#[cfg(not(test))]
#[no_mangle]
pub unsafe extern "C" fn runtime_entry(
    argc: i32,
    argv: *const *const c_char,
    env: *const *const c_char,
) -> ! {
    use crate::sys::hermit::thread_local_dtor::run_dtors;
    extern "C" {
        fn main(argc: isize, argv: *const *const c_char) -> i32;
    }

    // initialize environment
    os::init_environment(env as *const *const i8);

    let result = main(argc as isize, argv);

    run_dtors();
    abi::exit(result);
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno {
        x if x == 13 as i32 => ErrorKind::PermissionDenied,
        x if x == 98 as i32 => ErrorKind::AddrInUse,
        x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
        x if x == 11 as i32 => ErrorKind::WouldBlock,
        x if x == 103 as i32 => ErrorKind::ConnectionAborted,
        x if x == 111 as i32 => ErrorKind::ConnectionRefused,
        x if x == 104 as i32 => ErrorKind::ConnectionReset,
        x if x == 17 as i32 => ErrorKind::AlreadyExists,
        x if x == 4 as i32 => ErrorKind::Interrupted,
        x if x == 22 as i32 => ErrorKind::InvalidInput,
        x if x == 2 as i32 => ErrorKind::NotFound,
        x if x == 107 as i32 => ErrorKind::NotConnected,
        x if x == 1 as i32 => ErrorKind::PermissionDenied,
        x if x == 32 as i32 => ErrorKind::BrokenPipe,
        x if x == 110 as i32 => ErrorKind::TimedOut,
        _ => ErrorKind::Other,
    }
}

pub fn cvt(result: i32) -> crate::io::Result<usize> {
    if result < 0 { Err(crate::io::Error::from_raw_os_error(-result)) } else { Ok(result as usize) }
}
<|endoftext|>


<commit_before>#![cfg(thiserror_nightly_testing)]
#![feature(backtrace)]

use std::backtrace::Backtrace;
use thiserror::Error;

pub mod structs {
    use super::*;

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptSourceNoBacktrace {
        #[source]
        source: Option<anyhow::Error>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptSourceAlwaysBacktrace {
        #[source]
        source: Option<anyhow::Error>,
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct NoSourceOptBacktrace {
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct AlwaysSourceOptBacktrace {
        source: anyhow::Error,
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptSourceOptBacktrace {
        #[source]
        source: Option<anyhow::Error>,
        #[backtrace]
        backtrace: Option<Backtrace>,
    }
}

pub mod enums {
    use super::*;

    #[derive(Error, Debug)]
    pub enum OptSourceNoBacktrace {
        #[error("...")]
        Test {
            #[source]
            source: Option<anyhow::Error>,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptSourceAlwaysBacktrace {
        #[error("...")]
        Test {
            #[source]
            source: Option<anyhow::Error>,
            backtrace: Backtrace,
        },
    }

    #[derive(Error, Debug)]
    pub enum NoSourceOptBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum AlwaysSourceOptBacktrace {
        #[error("...")]
        Test {
            source: anyhow::Error,
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptSourceOptBacktrace {
        #[error("...")]
        Test {
            #[source]
            source: Option<anyhow::Error>,
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }
}
<commit_msg>Make test_option appear as ignored or passing<commit_after>#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]

#[cfg(thiserror_nightly_testing)]
pub mod structs {
    use std::backtrace::Backtrace;
    use thiserror::Error;

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptSourceNoBacktrace {
        #[source]
        source: Option<anyhow::Error>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptSourceAlwaysBacktrace {
        #[source]
        source: Option<anyhow::Error>,
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct NoSourceOptBacktrace {
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct AlwaysSourceOptBacktrace {
        source: anyhow::Error,
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptSourceOptBacktrace {
        #[source]
        source: Option<anyhow::Error>,
        #[backtrace]
        backtrace: Option<Backtrace>,
    }
}

#[cfg(thiserror_nightly_testing)]
pub mod enums {
    use std::backtrace::Backtrace;
    use thiserror::Error;

    #[derive(Error, Debug)]
    pub enum OptSourceNoBacktrace {
        #[error("...")]
        Test {
            #[source]
            source: Option<anyhow::Error>,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptSourceAlwaysBacktrace {
        #[error("...")]
        Test {
            #[source]
            source: Option<anyhow::Error>,
            backtrace: Backtrace,
        },
    }

    #[derive(Error, Debug)]
    pub enum NoSourceOptBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum AlwaysSourceOptBacktrace {
        #[error("...")]
        Test {
            source: anyhow::Error,
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptSourceOptBacktrace {
        #[error("...")]
        Test {
            #[source]
            source: Option<anyhow::Error>,
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }
}

#[test]
#[cfg_attr(not(thiserror_nightly_testing), ignore)]
fn test_option() {}
<|endoftext|>


<commit_before>#![cfg_attr(all(feature = "nightly", test), feature(test))]

#[cfg(all(feature = "nightly", test))]
extern crate test;

use std::collections::HashMap;
use std::error::Error;

use failure::Fail;

type LimitAmount = u64;

#[derive(Debug, PartialEq, Fail)]
#[fail(display = "An error occurred.")]
pub struct LimitError {
    kind: LimitErrorKind,
}

#[derive(Debug, PartialEq)]
pub enum LimitErrorKind {
    LimitUnavailable,
    WrongEntity,
}

impl LimitError {
    pub fn new(kind: LimitErrorKind) -> Self {
        LimitError { kind: kind }
    }
}

pub struct TwoWayLimit {
    left: LimitAmount,
    right: LimitAmount,
    double: LimitAmount,
}

impl TwoWayLimit {
    fn new(left: LimitAmount, right: LimitAmount) -> TwoWayLimit {
        TwoWayLimit {
            left: left,
            right: right,
            double: left.min(right),
        }
    }

    pub fn try_deduct(&mut self, amount: LimitAmount) -> Result<(), Box<dyn Error>> {
        if self.double >= amount {
            self.left -= amount;
            self.right -= amount;
            self.double -= amount;
            return Ok(());
        } else {
            return Err(Box::new(
                LimitError::new(LimitErrorKind::LimitUnavailable).compat(),
            ));
        }
    }

    pub fn try_deduct_available(
        &mut self,
        amount: LimitAmount,
    ) -> Result<LimitAmount, Box<dyn std::error::Error>> {
        let available = amount.min(self.double);
        if available == 0 {
            return Err(Box::new(
                LimitError::new(LimitErrorKind::LimitUnavailable).compat(),
            ));
        }
        self.left -= available;
        self.right -= available;
        self.double -= available;
        return Ok(available);
    }
}

impl Default for TwoWayLimit {
    fn default() -> TwoWayLimit {
        TwoWayLimit::new(0, 0)
    }
}

pub struct LimitManager {
    limits: HashMap<usize, TwoWayLimit>,
    shift: usize,
}

impl LimitManager {
    pub fn new(capacity: usize, shift: usize) -> Self {
        LimitManager {
            limits: HashMap::with_capacity(capacity),
            shift: shift,
        }
    }

    pub fn insert(
        &mut self,
        left_entity: usize,
        left_amount: LimitAmount,
        right_entity: usize,
        right_amount: LimitAmount,
    ) -> Result<(), Box<dyn Error>> {
        if left_entity >= right_entity {
            return Err(Box::new(
                LimitError::new(LimitErrorKind::WrongEntity).compat(),
            ));
        }
        let limit = TwoWayLimit::new(left_amount, right_amount);
        self.limits
            .insert(left_entity * self.shift + right_entity, limit);
        Ok(())
    }

    pub fn deduct(
        &mut self,
        left_entity: usize,
        right_entity: usize,
        amount: LimitAmount,
    ) -> Result<(), Box<dyn Error>> {
        if let Some(limit) = self
            .limits
            .get_mut(&(left_entity * self.shift + right_entity))
        {
            return limit.try_deduct(amount);
        } else {
            return Err(Box::new(
                LimitError::new(LimitErrorKind::WrongEntity).compat(),
            ));
        }
    }
}

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

    #[test]
    fn test_try_deduct() {
        let mut limit = TwoWayLimit::new(10000, 10000);

        assert_eq!(10000, limit.double);
        assert!(limit.try_deduct(10001).is_err());

        assert_eq!((), limit.try_deduct(10000).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(0, limit.right);

        let mut limit = TwoWayLimit::new(5000, 10000);

        assert_eq!(5000, limit.double);
        assert!(limit.try_deduct(5001).is_err());

        assert_eq!((), limit.try_deduct(3000).unwrap());
        assert_eq!(2000, limit.double);
        assert_eq!(2000, limit.left);
        assert_eq!(7000, limit.right);
    }

    #[test]
    fn test_try_deduct_available() {
        let mut limit = TwoWayLimit::new(10000, 10000);

        assert_eq!(10000, limit.double);
        assert_eq!(10000, limit.try_deduct_available(10001).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(0, limit.right);

        let mut limit = TwoWayLimit::new(10000, 10000);

        assert_eq!(10000, limit.try_deduct_available(10000).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(0, limit.right);

        let mut limit = TwoWayLimit::new(5000, 10000);

        assert_eq!(3000, limit.try_deduct_available(3000).unwrap());
        assert_eq!(2000, limit.double);
        assert_eq!(2000, limit.left);
        assert_eq!(7000, limit.right);

        assert_eq!(2000, limit.try_deduct_available(8000).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(5000, limit.right);
    }

    #[test]
    fn test_limit_manager() {
        let mut limit_manager = LimitManager::new(10, 100_000);
        assert!(limit_manager.insert(1000, 10000, 100, 1000).is_err());

        assert!(limit_manager.insert(1000, 5000, 2000, 10000).is_ok());
        assert!(limit_manager.insert(1000, 50000, 3000, 10000).is_ok());

        assert!(limit_manager.deduct(1000, 1000, 3000).is_err());
        assert!(limit_manager.deduct(1000, 2000, 3000).is_ok());
        assert!(limit_manager.deduct(1000, 2000, 3000).is_err());
    }
}

#[cfg(all(feature = "nightly", test))]
mod bench {
    use super::*;
    use rand::{thread_rng, Rng};
    use test::Bencher;

    #[bench]
    fn bench_limit_manager(b: &mut Bencher) {
        let entity_count = 10000;
        let shift = 100_000;
        let test_count = 100_000;

        let mut limit_manager = init_limit_manager(entity_count, shift);
        let deduct_queue = init_deduct_queue(test_count, entity_count);

        b.iter(|| {
            deduct_queue.iter().for_each(|(left, right, amount)| {
                let _ = limit_manager.deduct(*left, *right, *amount);
            })
        });
    }

    fn init_limit_manager(entity_count: usize, entity_sqno_shift: usize) -> LimitManager {
        let mut rng = thread_rng();
        let mut limit_manager = LimitManager::new(entity_count, entity_sqno_shift);

        for i in 0..entity_count {
            for j in (i + 1)..entity_count {
                let left_amount = rng.gen_range(1, 101) * 1000;
                let right_amount = rng.gen_range(1, 101) * 1000;
                let _ = limit_manager.insert(i, left_amount, j, right_amount);
            }
        }

        return limit_manager;
    }

    fn init_deduct_queue(
        queue_size: usize,
        entity_count: usize,
    ) -> Vec<(usize, usize, LimitAmount)> {
        let mut queue = Vec::with_capacity(queue_size);
        let mut rng = thread_rng();

        for _ in 0..queue_size {
            let mut i = rng.gen_range(0, entity_count);
            let j;
            if i + 1 == entity_count {
                j = i;
                i = j - 1;
            } else {
                j = rng.gen_range(i + 1, entity_count);
            }
            let amount = rng.gen_range(1, 201) * 1000;
            queue.push((i, j, amount));
        }

        return queue;
    }
}
<commit_msg>a benchmark test example<commit_after>#![cfg_attr(all(feature = "nightly", test), feature(test))]

#[cfg(all(feature = "nightly", test))]
extern crate test;

use std::collections::HashMap;
use std::error::Error;
use std::fmt::{self, Display};

type LimitAmount = u64;

#[derive(Debug)]
pub struct LimitError {
    kind: LimitErrorKind,
}

impl LimitError {
    pub fn new(kind: LimitErrorKind) -> Self {
        LimitError { kind: kind }
    }
}

impl Error for LimitError {}

impl Display for LimitError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "LimitError")
    }
}

#[derive(Debug, PartialEq)]
pub enum LimitErrorKind {
    LimitUnavailable,
    WrongEntity,
}

#[derive(Debug)]
pub struct TwoWayLimit {
    left: LimitAmount,
    right: LimitAmount,
    double: LimitAmount,
}

impl TwoWayLimit {
    fn new(left: LimitAmount, right: LimitAmount) -> TwoWayLimit {
        TwoWayLimit {
            left: left,
            right: right,
            double: left.min(right),
        }
    }

    pub fn try_deduct(&mut self, amount: LimitAmount) -> Result<(), LimitError> {
        if self.double >= amount {
            self.left -= amount;
            self.right -= amount;
            self.double -= amount;
            return Ok(());
        } else {
            return Err(LimitError::new(LimitErrorKind::LimitUnavailable));
        }
    }

    pub fn try_deduct_available(&mut self, amount: LimitAmount) -> Result<LimitAmount, LimitError> {
        let available = amount.min(self.double);
        if available == 0 {
            return Err(LimitError::new(LimitErrorKind::LimitUnavailable));
        }
        self.left -= available;
        self.right -= available;
        self.double -= available;
        return Ok(available);
    }
}

impl Default for TwoWayLimit {
    fn default() -> TwoWayLimit {
        TwoWayLimit::new(0, 0)
    }
}

pub struct LimitManager {
    limits: HashMap<usize, TwoWayLimit>,
    shift: usize,
}

impl LimitManager {
    pub fn new(capacity: usize, shift: usize) -> Self {
        LimitManager {
            limits: HashMap::with_capacity(capacity),
            shift: shift,
        }
    }

    pub fn insert(
        &mut self,
        left_entity: usize,
        left_amount: LimitAmount,
        right_entity: usize,
        right_amount: LimitAmount,
    ) -> Result<(), LimitError> {
        if left_entity >= right_entity {
            return Err(LimitError::new(LimitErrorKind::WrongEntity));
        }
        let limit = TwoWayLimit::new(left_amount, right_amount);
        self.limits
            .insert(left_entity * self.shift + right_entity, limit);
        Ok(())
    }

    pub fn deduct(
        &mut self,
        left_entity: usize,
        right_entity: usize,
        amount: LimitAmount,
    ) -> Result<(), LimitError> {
        if let Some(limit) = self
            .limits
            .get_mut(&(left_entity * self.shift + right_entity))
        {
            return limit.try_deduct(amount);
        } else {
            return Err(LimitError::new(LimitErrorKind::WrongEntity));
        }
    }
}

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

    #[test]
    fn test_try_deduct() {
        let mut limit = TwoWayLimit::new(10000, 10000);

        assert_eq!(10000, limit.double);
        assert!(limit.try_deduct(10001).is_err());

        assert_eq!((), limit.try_deduct(10000).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(0, limit.right);

        let mut limit = TwoWayLimit::new(5000, 10000);

        assert_eq!(5000, limit.double);
        assert!(limit.try_deduct(5001).is_err());

        assert_eq!((), limit.try_deduct(3000).unwrap());
        assert_eq!(2000, limit.double);
        assert_eq!(2000, limit.left);
        assert_eq!(7000, limit.right);
    }

    #[test]
    fn test_try_deduct_available() {
        let mut limit = TwoWayLimit::new(10000, 10000);

        assert_eq!(10000, limit.double);
        assert_eq!(10000, limit.try_deduct_available(10001).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(0, limit.right);

        let mut limit = TwoWayLimit::new(10000, 10000);

        assert_eq!(10000, limit.try_deduct_available(10000).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(0, limit.right);

        let mut limit = TwoWayLimit::new(5000, 10000);

        assert_eq!(3000, limit.try_deduct_available(3000).unwrap());
        assert_eq!(2000, limit.double);
        assert_eq!(2000, limit.left);
        assert_eq!(7000, limit.right);

        assert_eq!(2000, limit.try_deduct_available(8000).unwrap());
        assert_eq!(0, limit.double);
        assert_eq!(0, limit.left);
        assert_eq!(5000, limit.right);
    }

    #[test]
    fn test_limit_manager() {
        let mut limit_manager = LimitManager::new(10, 100_000);
        assert!(limit_manager.insert(1000, 10000, 100, 1000).is_err());

        assert!(limit_manager.insert(1000, 5000, 2000, 10000).is_ok());
        assert!(limit_manager.insert(1000, 50000, 3000, 10000).is_ok());

        assert!(limit_manager.deduct(1000, 1000, 3000).is_err());
        assert!(limit_manager.deduct(1000, 2000, 3000).is_ok());
        assert!(limit_manager.deduct(1000, 2000, 3000).is_err());
    }
}

#[cfg(all(feature = "nightly", test))]
mod bench {
    use super::*;
    use rand::{thread_rng, Rng};
    use test::Bencher;

    #[bench]
    fn bench_limit_manager(b: &mut Bencher) {
        let entity_count = 10000;
        let shift = 10_0000;
        let test_count = 10_0000;

        let mut limit_manager = init_limit_manager(entity_count, shift);
        let deduct_queue = init_deduct_queue(test_count, entity_count);

        b.iter(|| {
            deduct_queue.iter().for_each(|(left, right, amount)| {
                let _ = limit_manager.deduct(*left, *right, *amount);
            });
        });
    }

    fn init_limit_manager(entity_count: usize, entity_sqno_shift: usize) -> LimitManager {
        let mut rng = thread_rng();
        let mut limit_manager = LimitManager::new(entity_count, entity_sqno_shift);

        for i in 0..entity_count {
            for j in (i + 1)..entity_count {
                let left_amount = rng.gen_range(1, 101) * 1000;
                let right_amount = rng.gen_range(1, 101) * 1000;
                let _ = limit_manager.insert(i, left_amount, j, right_amount);
            }
        }

        return limit_manager;
    }

    fn init_deduct_queue(
        queue_size: usize,
        entity_count: usize,
    ) -> Vec<(usize, usize, LimitAmount)> {
        let mut queue = Vec::with_capacity(queue_size);
        let mut rng = thread_rng();

        for _ in 0..queue_size {
            let mut i = rng.gen_range(0, entity_count);
            let j;
            if i + 1 == entity_count {
                j = i;
                i = j - 1;
            } else {
                j = rng.gen_range(i + 1, entity_count);
            }
            let amount = rng.gen_range(1, 51) * 1000;
            queue.push((i, j, amount));
        }

        return queue;
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate criterion;
#[macro_use]
extern crate serde_derive;

use std::collections::BTreeMap;

use criterion::Criterion;
use handlebars::{to_json, Handlebars, Template};
use serde_json::value::Value as Json;

#[derive(Serialize)]
struct DataWrapper {
    v: String,
}

#[derive(Serialize)]
struct RowWrapper {
    real: Vec<DataWrapper>,
    dummy: Vec<DataWrapper>,
}

static SOURCE: &'static str = "

    <title>{{year}}</title>

CSL {{year}}

    {{#each teams}}

      {{name}}: {{score}}

    {{/each}}

";

fn make_data() -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), to_json("2015"));

    let mut teams = Vec::new();

    for v in vec![
        ("Jiangsu", 43u16),
        ("Beijing", 27u16),
        ("Guangzhou", 22u16),
        ("Shandong", 12u16),
    ]
    .iter()
    {
        let (name, score) = *v;
        let mut t = BTreeMap::new();
        t.insert("name".to_string(), to_json(name));
        t.insert("score".to_string(), to_json(score));
        teams.push(t)
    }

    data.insert("teams".to_string(), to_json(&teams));
    data
}

fn parse_template(c: &mut Criterion) {
    c.bench_function("parse_template", move |b| {
        b.iter(|| Template::compile(SOURCE).ok().unwrap())
    });
}

fn render_template(c: &mut Criterion) {
    let mut handlebars = Handlebars::new();
    handlebars
        .register_template_string("table", SOURCE)
        .ok()
        .expect("Invalid template format");

    let data = make_data();
    c.bench_function("render_template", move |b| {
        b.iter(|| handlebars.render("table", &data).ok().unwrap())
    });
}

fn large_loop_helper(c: &mut Criterion) {
    let mut handlebars = Handlebars::new();
    handlebars
        .register_template_string("test", "BEFORE\n{{#each real}}{{this.v}}{{/each}}AFTER")
        .ok()
        .expect("Invalid template format");

    let real: Vec<DataWrapper> = (1..1000)
        .into_iter()
        .map(|i| DataWrapper {
            v: format!("n={}", i),
        })
        .collect();
    let dummy: Vec<DataWrapper> = (1..1000)
        .into_iter()
        .map(|i| DataWrapper {
            v: format!("n={}", i),
        })
        .collect();
    let rows = RowWrapper { real, dummy };

    c.bench_function("large_loop_helper", move |b| {
        b.iter(|| handlebars.render("test", &rows).ok().unwrap())
    });
}

criterion_group!(benches, parse_template, render_template, large_loop_helper);
criterion_main!(benches);
<commit_msg>(test) add nested loop benchmark<commit_after>#[macro_use]
extern crate criterion;
#[macro_use]
extern crate serde_derive;

use std::collections::BTreeMap;

use criterion::Criterion;
use handlebars::{to_json, Handlebars, Template};
use serde_json::value::Value as Json;

#[derive(Serialize)]
struct DataWrapper {
    v: String,
}

#[derive(Serialize)]
struct RowWrapper {
    real: Vec<DataWrapper>,
    dummy: Vec<DataWrapper>,
}

#[derive(Serialize)]
struct NestedRowWrapper {
    parent: Vec<Vec<DataWrapper>>,
}

static SOURCE: &'static str = "

    <title>{{year}}</title>

CSL {{year}}

    {{#each teams}}

      {{name}}: {{score}}

    {{/each}}

";

fn make_data() -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), to_json("2015"));

    let mut teams = Vec::new();

    for v in vec![
        ("Jiangsu", 43u16),
        ("Beijing", 27u16),
        ("Guangzhou", 22u16),
        ("Shandong", 12u16),
    ]
    .iter()
    {
        let (name, score) = *v;
        let mut t = BTreeMap::new();
        t.insert("name".to_string(), to_json(name));
        t.insert("score".to_string(), to_json(score));
        teams.push(t)
    }

    data.insert("teams".to_string(), to_json(&teams));
    data
}

fn parse_template(c: &mut Criterion) {
    c.bench_function("parse_template", move |b| {
        b.iter(|| Template::compile(SOURCE).ok().unwrap())
    });
}

fn render_template(c: &mut Criterion) {
    let mut handlebars = Handlebars::new();
    handlebars
        .register_template_string("table", SOURCE)
        .ok()
        .expect("Invalid template format");

    let data = make_data();
    c.bench_function("render_template", move |b| {
        b.iter(|| handlebars.render("table", &data).ok().unwrap())
    });
}

fn large_loop_helper(c: &mut Criterion) {
    let mut handlebars = Handlebars::new();
    handlebars
        .register_template_string("test", "BEFORE\n{{#each real}}{{this.v}}{{/each}}AFTER")
        .ok()
        .expect("Invalid template format");

    let real: Vec<DataWrapper> = (1..1000)
        .map(|i| DataWrapper {
            v: format!("n={}", i),
        })
        .collect();
    let dummy: Vec<DataWrapper> = (1..1000)
        .map(|i| DataWrapper {
            v: format!("n={}", i),
        })
        .collect();
    let rows = RowWrapper { real, dummy };

    c.bench_function("large_loop_helper", move |b| {
        b.iter(|| handlebars.render("test", &rows).ok().unwrap())
    });
}

fn large_nested_loop(c: &mut Criterion) {
    let mut handlebars = Handlebars::new();
    handlebars
        .register_template_string(
            "test",
            "BEFORE\n{{#each parent as |child|}}{{#each child}}{{this.v}}{{/each}}{{/each}}AFTER",
        )
        .ok()
        .expect("Invalid template format");

    let parent: Vec<Vec<DataWrapper>> = (1..100)
        .map(|_| {
            (1..10)
                .map(|v| DataWrapper {
                    v: format!("v={}", v),
                })
                .collect()
        })
        .collect();

    let rows = NestedRowWrapper { parent };

    c.bench_function("large_nested_loop", move |b| {
        b.iter(|| handlebars.render("test", &rows).ok().unwrap())
    });
}

criterion_group!(
    benches,
    parse_template,
    render_template,
    large_loop_helper,
    large_nested_loop
);
criterion_main!(benches);
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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 mio::Timeout as MioTimeout;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use std::borrow::Borrow;
use std::io;
use std::fmt;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::cmp;
use std::default::Default;

use messages::RawMessage;
use blockchain::SharedNodeState;
use super::connection::{Connection, IncomingConnection, OutgoingConnection};
use super::{Timeout, InternalTimeout, EventLoop, EventHandler, Event};

pub use mio::{EventSet, PollOpt, Token};

pub type PeerId = Token;

const SERVER_ID: PeerId = Token(1);
const RECONNECT_GROW_FACTOR: f32 = 2.0;

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

impl Default for NetworkConfiguration {
    fn default() -> NetworkConfiguration {
        NetworkConfiguration {
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_keep_alive: None,
            tcp_nodelay: false,
            tcp_reconnect_timeout: 500,
            tcp_reconnect_timeout_max: 600000,
        }
    }
}

// TODO Implement generic ConnectionPool struct to avoid copy paste.
// Write proper code to configure outgoing streams
pub struct Network {
    api_state: SharedNodeState,
    config: NetworkConfiguration,
    listen_address: SocketAddr,
    listener: Option<TcpListener>,

    incoming: Slab<IncomingConnection>,
    outgoing: Slab<OutgoingConnection>,
    // FIXME addresses only needs for outgoing connections
    addresses: HashMap<SocketAddr, PeerId>,

    reconnects: HashMap<SocketAddr, MioTimeout>,
}

enum PeerKind {
    Server,
    Incoming,
    Outgoing,
}

fn make_io_error<T: Borrow<str>>(s: T) -> io::Error {
    io::Error::new(io::ErrorKind::Other, s.borrow())
}

impl Network {
    pub fn with_config(
        address: SocketAddr,
        config: NetworkConfiguration,
        api_state: SharedNodeState,
    ) -> Network {
        Network {
            api_state,
            config: config,
            listen_address: address,
            listener: None,

            incoming: Slab::new_starting_at(Token(2), config.max_incoming_connections),
            outgoing: Slab::new_starting_at(
                Token(2 + config.max_incoming_connections),
                config.max_outgoing_connections,
            ),
            addresses: HashMap::new(),

            reconnects: HashMap::new(),
        }
    }

    pub fn address(&self) -> &SocketAddr {
        &self.listen_address
    }

    // TODO use error trait
    pub fn bind<H: EventHandler>(&mut self, event_loop: &mut EventLoop<H>) -> io::Result<()> {
        if self.listener.is_some() {
            return Err(make_io_error("Already bind"));
        }
        let listener = TcpListener::bind(&self.listen_address)?;
        event_loop.register(
            &listener,
            SERVER_ID,
            EventSet::readable(),
            PollOpt::edge(),
        )?;
        self.listener = Some(listener);
        Ok(())
    }

    // TODO: Use ticks for fast reregistering sockets
    // TODO: Implement Connections collection with (re)registering
    pub fn io<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        handler: &mut H,
        id: PeerId,
        set: EventSet,
    ) -> io::Result<()> {

        match self.peer_kind(id) {
            PeerKind::Server => {
                // Accept new connections
                // FIXME: Fail-safe accepting of new connections?
                let pair = match self.listener {
                    Some(ref listener) => listener.accept()?,
                    None => None,
                };
                if let Some((mut stream, address)) = pair {
                    self.configure_stream(&mut stream)?;
                    let peer = IncomingConnection::new(stream, address);
                    self.add_incoming_connection(event_loop, peer)?;

                    trace!(
                        "{}: Accepted incoming connection from {} id: {}",
                        self.address(),
                        address,
                        id.0
                    );
                }
                return Ok(());
            }
            PeerKind::Incoming => {
                if !self.incoming.contains(id) {
                    return Ok(());
                }

                if set.is_hup() | set.is_error() {
                    trace!(
                        "{}: incoming connection with {} address is closed",
                        self.address(),
                        self.incoming[id].address()
                    );

                    self.remove_incoming_connection(event_loop, id);
                    return Ok(());
                }

                if set.is_readable() {
                    loop {
                        match self.incoming[id].try_read() {
                            Ok(Some(buf)) => {
                                let msg = RawMessage::new(buf);
                                handler.handle_event(Event::Incoming(msg));
                            }
                            Ok(None) => return Ok(()),
                            Err(e) => {
                                self.remove_incoming_connection(event_loop, id);
                                return Err(e);
                            }
                        };
                    }
                }
            }
            PeerKind::Outgoing => {
                if !self.outgoing.contains(id) {
                    return Ok(());
                }

                if set.is_hup() | set.is_error() {
                    let address = *self.outgoing[id].address();

                    trace!(
                        "{}: outgoing connection with address {} is closed",
                        self.address(),
                        self.outgoing[id].address()
                    );

                    self.remove_outgoing_connection(event_loop, id);
                    if !self.reconnects.contains_key(&address) {
                        handler.handle_event(Event::Disconnected(address));
                    }
                    return Ok(());
                }

                if set.is_writable() {
                    let address = *self.outgoing[id].address();
                    let r = {
                        // Write data into socket
                        self.outgoing[id].try_write()?;
                        event_loop.reregister(
                            self.outgoing[id].socket(),
                            id,
                            self.outgoing[id].interest(),
                            PollOpt::edge(),
                        )?;
                        Ok(())
                    };
                    if let Err(e) = r {
                        self.remove_outgoing_connection(event_loop, id);
                        handler.handle_event(Event::Disconnected(address));
                        return Err(e);
                    }

                    if self.mark_connected(event_loop, id) {
                        trace!("{}: Handle connected with {}", self.address(), address);
                        handler.handle_event(Event::Connected(address));
                    }
                }
            }
        }
        Ok(())
    }

    pub fn tick<H: EventHandler>(&mut self, _: &mut EventLoop<H>) {}

    pub fn send_to<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: &SocketAddr,
        message: RawMessage,
    ) -> io::Result<()> {
        match self.get_outgoing_peer(address) {
            Ok(id) => {
                self.outgoing[id]
                    .send(message)
                    .and_then(|_| {
                        event_loop.reregister(
                            self.outgoing[id].socket(),
                            id,
                            self.outgoing[id].interest(),
                            PollOpt::edge(),
                        )?;
                        self.mark_connected(event_loop, id);
                        Ok(())
                    })
                    .or_else(|e| {
                        self.remove_outgoing_connection(event_loop, id);
                        Err(e)
                    })
            }
            Err(e) => Err(e),
        }
    }

    pub fn connect<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: &SocketAddr,
    ) -> io::Result<()> {
        if !self.is_connected(address) {
            self.add_reconnect_request(event_loop, *address)?;

            let mut stream = TcpStream::connect(address)?;
            self.configure_stream(&mut stream)?;
            let peer = OutgoingConnection::new(stream, *address);
            let id = self.add_outgoing_connection(event_loop, peer)?;

            trace!(
                "{}: Establish connection with {}, id: {}",
                self.address(),
                address,
                id.0
            );
        }
        Ok(())
    }

    pub fn is_connected(&self, address: &SocketAddr) -> bool {
        self.addresses.contains_key(address)
    }

    pub fn handle_timeout<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        timeout: InternalTimeout,
    ) {
        match timeout {
            InternalTimeout::Reconnect(addr, delay) => {
                if self.reconnects.contains_key(&addr) {
                    trace!("Try to reconnect with '{}' delay", delay);

                    if let Err(e) = self.connect(event_loop, &addr) {
                        error!(
                            "{}: Unable to create connection to address '{}', error: {:?}",
                            self.address(),
                            addr,
                            e
                        );
                    }

                    let delay = cmp::min(
                        (delay as f32 * RECONNECT_GROW_FACTOR) as u64,
                        self.config.tcp_reconnect_timeout_max,
                    );

                    if let Err(e) = self.add_reconnect_timeout(event_loop, addr, delay) {
                        error!("{}: Unable to add timeout, error: {:?}", self.address(), e);
                    }
                }
            }
        }
    }

    fn peer_kind(&self, id: PeerId) -> PeerKind {
        if id == SERVER_ID {
            PeerKind::Server
        } else if id.0 >= (2 + self.config.max_incoming_connections) {
            PeerKind::Outgoing
        } else {
            PeerKind::Incoming
        }
    }

    fn get_outgoing_peer(&self, addr: &SocketAddr) -> io::Result<PeerId> {
        if let Some(id) = self.addresses.get(addr) {
            return Ok(*id);
        };
        Err(make_io_error(format!(
            "{}: Outgoing peer not found {}",
            self.address(),
            addr
        )))
    }

    fn add_incoming_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        connection: IncomingConnection,
    ) -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.incoming.insert(connection).map_err(|_| {
            make_io_error("Maximum incoming connections")
        })?;
        self.addresses.insert(address, id);
        self.api_state.add_incoming_connection(address);

        let r = event_loop.register(
            self.incoming[id].socket(),
            id,
            self.incoming[id].interest(),
            PollOpt::edge(),
        );

        if let Err(e) = r {
            self.remove_incoming_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn add_outgoing_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        connection: OutgoingConnection,
    ) -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.outgoing.insert(connection).map_err(|_| {
            make_io_error("Maximum outgoing connections")
        })?;
        self.addresses.insert(address, id);
        self.api_state.add_outgoing_connection(address);

        let r = event_loop.register(
            self.outgoing[id].socket(),
            id,
            self.outgoing[id].interest() | EventSet::writable(),
            PollOpt::edge(),
        );

        if let Err(e) = r {
            self.remove_outgoing_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn remove_incoming_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        id: PeerId,
    ) {
        let addr = *self.incoming[id].address();
        self.addresses.remove(&addr);
        self.api_state.remove_incoming_connection(&addr);

        if let Some(connection) = self.incoming.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!(
                    "{}: Unable to deregister incoming connection, id: {}, error: {:?}",
                    self.address(),
                    id.0,
                    e
                );
            }
        }
    }

    fn remove_outgoing_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        id: PeerId,
    ) {
        let addr = *self.outgoing[id].address();
        self.addresses.remove(&addr);
        self.api_state.remove_outgoing_connection(&addr);

        if let Some(connection) = self.outgoing.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!(
                    "{}: Unable to deregister outgoing connection, id: {}, error: {:?}",
                    self.address(),
                    id.0,
                    e
                );
            }
        }
    }

    fn configure_stream(&self, stream: &mut TcpStream) -> io::Result<()> {
        stream.take_socket_error()?;
        stream.set_keepalive(self.config.tcp_keep_alive)?;
        stream.set_nodelay(self.config.tcp_nodelay)?;
        stream.take_socket_error()
    }

    fn add_reconnect_request<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: SocketAddr,
    ) -> io::Result<()> {
        if !self.reconnects.contains_key(&address) {
            let delay = self.config.tcp_reconnect_timeout;
            return self.add_reconnect_timeout(event_loop, address, delay);
        }
        Ok(())
    }

    fn add_reconnect_timeout<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: SocketAddr,
        delay: u64,
    ) -> io::Result<()> {
        trace!(
            "{}: Add reconnect timeout to {}, delay = {}",
            self.address(),
            address,
            delay
        );
        let reconnect = Timeout::Internal(InternalTimeout::Reconnect(address, delay));
        let timeout = event_loop.timeout_ms(reconnect, delay).map_err(|e| {
            make_io_error(format!("A mio error occurred {:?}", e))
        })?;
        self.reconnects.insert(address, timeout);
        self.api_state.add_reconnect_timeout(address, delay);

        Ok(())
    }

    fn mark_connected<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        id: Token,
    ) -> bool {
        let address = *self.outgoing[id].address();
        self.clear_reconnect_request(event_loop, &address)
    }

    fn clear_reconnect_request<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        addr: &SocketAddr,
    ) -> bool {
        if let Some(timeout) = self.reconnects.remove(addr) {
            self.api_state.remove_reconnect_timeout(addr);
            trace!("{}: Clear reconnect timeout to={}", self.address(), addr);
            event_loop.clear_timeout(timeout);
            return true;
        }
        false
    }
}

impl fmt::Debug for Network {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Network {{ listen_address: {:?}, listener: {:?}, incoming: {:?}, \
        outgoing: {:?}, addresses: {:?}, reconnects: {{ .. }} }}",
            self.listen_address,
            self.listener,
            self.incoming,
            self.outgoing,
            self.addresses
        )
    }
}
<commit_msg>fix reconnect bug<commit_after>// Copyright 2017 The Exonum Team
//
// 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 mio::Timeout as MioTimeout;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use std::borrow::Borrow;
use std::io;
use std::fmt;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::cmp;
use std::default::Default;

use messages::RawMessage;
use blockchain::SharedNodeState;
use super::connection::{Connection, IncomingConnection, OutgoingConnection};
use super::{Timeout, InternalTimeout, EventLoop, EventHandler, Event};

pub use mio::{EventSet, PollOpt, Token};

pub type PeerId = Token;

const SERVER_ID: PeerId = Token(1);
const RECONNECT_GROW_FACTOR: f32 = 2.0;

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

impl Default for NetworkConfiguration {
    fn default() -> NetworkConfiguration {
        NetworkConfiguration {
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_keep_alive: None,
            tcp_nodelay: false,
            tcp_reconnect_timeout: 500,
            tcp_reconnect_timeout_max: 600000,
        }
    }
}

// TODO Implement generic ConnectionPool struct to avoid copy paste.
// Write proper code to configure outgoing streams
pub struct Network {
    api_state: SharedNodeState,
    config: NetworkConfiguration,
    listen_address: SocketAddr,
    listener: Option<TcpListener>,

    incoming: Slab<IncomingConnection>,
    outgoing: Slab<OutgoingConnection>,
    // FIXME addresses only needs for outgoing connections
    addresses: HashMap<SocketAddr, PeerId>,

    reconnects: HashMap<SocketAddr, MioTimeout>,
}

enum PeerKind {
    Server,
    Incoming,
    Outgoing,
}

fn make_io_error<T: Borrow<str>>(s: T) -> io::Error {
    io::Error::new(io::ErrorKind::Other, s.borrow())
}

impl Network {
    pub fn with_config(
        address: SocketAddr,
        config: NetworkConfiguration,
        api_state: SharedNodeState,
    ) -> Network {
        Network {
            api_state,
            config: config,
            listen_address: address,
            listener: None,

            incoming: Slab::new_starting_at(Token(2), config.max_incoming_connections),
            outgoing: Slab::new_starting_at(
                Token(2 + config.max_incoming_connections),
                config.max_outgoing_connections,
            ),
            addresses: HashMap::new(),

            reconnects: HashMap::new(),
        }
    }

    pub fn address(&self) -> &SocketAddr {
        &self.listen_address
    }

    // TODO use error trait
    pub fn bind<H: EventHandler>(&mut self, event_loop: &mut EventLoop<H>) -> io::Result<()> {
        if self.listener.is_some() {
            return Err(make_io_error("Already bind"));
        }
        let listener = TcpListener::bind(&self.listen_address)?;
        event_loop.register(
            &listener,
            SERVER_ID,
            EventSet::readable(),
            PollOpt::level(),
        )?;
        self.listener = Some(listener);
        Ok(())
    }

    // TODO: Use ticks for fast reregistering sockets
    // TODO: Implement Connections collection with (re)registering
    pub fn io<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        handler: &mut H,
        id: PeerId,
        set: EventSet,
    ) -> io::Result<()> {

        match self.peer_kind(id) {
            PeerKind::Server => {
                // Accept new connections
                // FIXME: Fail-safe accepting of new connections?
                let pair = match self.listener {
                    Some(ref listener) => listener.accept()?,
                    None => None,
                };
                if let Some((mut stream, address)) = pair {
                    self.configure_stream(&mut stream)?;
                    let peer = IncomingConnection::new(stream, address);
                    self.add_incoming_connection(event_loop, peer)?;

                    trace!(
                        "{}: Accepted incoming connection from {} id: {}",
                        self.address(),
                        address,
                        id.0
                    );
                }
                return Ok(());
            }
            PeerKind::Incoming => {
                if !self.incoming.contains(id) {
                    return Ok(());
                }

                if set.is_hup() | set.is_error() {
                    trace!(
                        "{}: incoming connection with {} address is closed",
                        self.address(),
                        self.incoming[id].address()
                    );

                    self.remove_incoming_connection(event_loop, id);
                    return Ok(());
                }

                if set.is_readable() {
                    loop {
                        match self.incoming[id].try_read() {
                            Ok(Some(buf)) => {
                                let msg = RawMessage::new(buf);
                                handler.handle_event(Event::Incoming(msg));
                            }
                            Ok(None) => return Ok(()),
                            Err(e) => {
                                self.remove_incoming_connection(event_loop, id);
                                return Err(e);
                            }
                        };
                    }
                }
            }
            PeerKind::Outgoing => {
                if !self.outgoing.contains(id) {
                    return Ok(());
                }

                if set.is_hup() | set.is_error() {
                    let address = *self.outgoing[id].address();

                    trace!(
                        "{}: outgoing connection with address {} is closed",
                        self.address(),
                        self.outgoing[id].address()
                    );

                    self.remove_outgoing_connection(event_loop, id);
                    if !self.reconnects.contains_key(&address) {
                        handler.handle_event(Event::Disconnected(address));
                    }
                    return Ok(());
                }

                if set.is_writable() {
                    let address = *self.outgoing[id].address();
                    let r = {
                        // Write data into socket
                        self.outgoing[id].try_write()?;
                        event_loop.reregister(
                            self.outgoing[id].socket(),
                            id,
                            self.outgoing[id].interest(),
                            PollOpt::edge(),
                        )?;
                        Ok(())
                    };
                    if let Err(e) = r {
                        self.remove_outgoing_connection(event_loop, id);
                        handler.handle_event(Event::Disconnected(address));
                        return Err(e);
                    }

                    if self.mark_connected(event_loop, id) {
                        trace!("{}: Handle connected with {}", self.address(), address);
                        handler.handle_event(Event::Connected(address));
                    }
                }
            }
        }
        Ok(())
    }

    pub fn tick<H: EventHandler>(&mut self, _: &mut EventLoop<H>) {}

    pub fn send_to<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: &SocketAddr,
        message: RawMessage,
    ) -> io::Result<()> {
        match self.get_outgoing_peer(address) {
            Ok(id) => {
                self.outgoing[id]
                    .send(message)
                    .and_then(|_| {
                        event_loop.reregister(
                            self.outgoing[id].socket(),
                            id,
                            self.outgoing[id].interest(),
                            PollOpt::edge(),
                        )?;
                        self.mark_connected(event_loop, id);
                        Ok(())
                    })
                    .or_else(|e| {
                        self.remove_outgoing_connection(event_loop, id);
                        Err(e)
                    })
            }
            Err(e) => Err(e),
        }
    }

    pub fn connect<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: &SocketAddr,
    ) -> io::Result<()> {
        if !self.is_connected(address) {
            self.add_reconnect_request(event_loop, *address)?;

            let mut stream = TcpStream::connect(address)?;
            self.configure_stream(&mut stream)?;
            let peer = OutgoingConnection::new(stream, *address);
            let id = self.add_outgoing_connection(event_loop, peer)?;

            trace!(
                "{}: Establish connection with {}, id: {}",
                self.address(),
                address,
                id.0
            );
        }
        Ok(())
    }

    pub fn is_connected(&self, address: &SocketAddr) -> bool {
        self.addresses.contains_key(address)
    }

    pub fn handle_timeout<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        timeout: InternalTimeout,
    ) {
        match timeout {
            InternalTimeout::Reconnect(addr, delay) => {
                if self.reconnects.contains_key(&addr) {
                    trace!("Try to reconnect with '{}' delay", delay);

                    if let Err(e) = self.connect(event_loop, &addr) {
                        error!(
                            "{}: Unable to create connection to address '{}', error: {:?}",
                            self.address(),
                            addr,
                            e
                        );
                    }

                    let delay = cmp::min(
                        (delay as f32 * RECONNECT_GROW_FACTOR) as u64,
                        self.config.tcp_reconnect_timeout_max,
                    );

                    if let Err(e) = self.add_reconnect_timeout(event_loop, addr, delay) {
                        error!("{}: Unable to add timeout, error: {:?}", self.address(), e);
                    }
                }
            }
        }
    }

    fn peer_kind(&self, id: PeerId) -> PeerKind {
        if id == SERVER_ID {
            PeerKind::Server
        } else if id.0 >= (2 + self.config.max_incoming_connections) {
            PeerKind::Outgoing
        } else {
            PeerKind::Incoming
        }
    }

    fn get_outgoing_peer(&self, addr: &SocketAddr) -> io::Result<PeerId> {
        if let Some(id) = self.addresses.get(addr) {
            return Ok(*id);
        };
        Err(make_io_error(format!(
            "{}: Outgoing peer not found {}",
            self.address(),
            addr
        )))
    }

    fn add_incoming_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        connection: IncomingConnection,
    ) -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.incoming.insert(connection).map_err(|_| {
            make_io_error("Maximum incoming connections")
        })?;
        self.addresses.insert(address, id);
        self.api_state.add_incoming_connection(address);

        let r = event_loop.register(
            self.incoming[id].socket(),
            id,
            self.incoming[id].interest(),
            PollOpt::edge(),
        );

        if let Err(e) = r {
            self.remove_incoming_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn add_outgoing_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        connection: OutgoingConnection,
    ) -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.outgoing.insert(connection).map_err(|_| {
            make_io_error("Maximum outgoing connections")
        })?;
        self.addresses.insert(address, id);
        self.api_state.add_outgoing_connection(address);

        let r = event_loop.register(
            self.outgoing[id].socket(),
            id,
            self.outgoing[id].interest() | EventSet::writable(),
            PollOpt::edge(),
        );

        if let Err(e) = r {
            self.remove_outgoing_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn remove_incoming_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        id: PeerId,
    ) {
        let addr = *self.incoming[id].address();
        self.addresses.remove(&addr);
        self.api_state.remove_incoming_connection(&addr);

        if let Some(connection) = self.incoming.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!(
                    "{}: Unable to deregister incoming connection, id: {}, error: {:?}",
                    self.address(),
                    id.0,
                    e
                );
            }
        }
    }

    fn remove_outgoing_connection<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        id: PeerId,
    ) {
        let addr = *self.outgoing[id].address();
        self.addresses.remove(&addr);
        self.api_state.remove_outgoing_connection(&addr);

        if let Some(connection) = self.outgoing.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!(
                    "{}: Unable to deregister outgoing connection, id: {}, error: {:?}",
                    self.address(),
                    id.0,
                    e
                );
            }
        }
    }

    fn configure_stream(&self, stream: &mut TcpStream) -> io::Result<()> {
        stream.take_socket_error()?;
        stream.set_keepalive(self.config.tcp_keep_alive)?;
        stream.set_nodelay(self.config.tcp_nodelay)?;
        stream.take_socket_error()
    }

    fn add_reconnect_request<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: SocketAddr,
    ) -> io::Result<()> {
        if !self.reconnects.contains_key(&address) {
            let delay = self.config.tcp_reconnect_timeout;
            return self.add_reconnect_timeout(event_loop, address, delay);
        }
        Ok(())
    }

    fn add_reconnect_timeout<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        address: SocketAddr,
        delay: u64,
    ) -> io::Result<()> {
        trace!(
            "{}: Add reconnect timeout to {}, delay = {}",
            self.address(),
            address,
            delay
        );
        let reconnect = Timeout::Internal(InternalTimeout::Reconnect(address, delay));
        let timeout = event_loop.timeout_ms(reconnect, delay).map_err(|e| {
            make_io_error(format!("A mio error occurred {:?}", e))
        })?;
        self.reconnects.insert(address, timeout);
        self.api_state.add_reconnect_timeout(address, delay);

        Ok(())
    }

    fn mark_connected<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        id: Token,
    ) -> bool {
        let address = *self.outgoing[id].address();
        self.clear_reconnect_request(event_loop, &address)
    }

    fn clear_reconnect_request<H: EventHandler>(
        &mut self,
        event_loop: &mut EventLoop<H>,
        addr: &SocketAddr,
    ) -> bool {
        if let Some(timeout) = self.reconnects.remove(addr) {
            self.api_state.remove_reconnect_timeout(addr);
            trace!("{}: Clear reconnect timeout to={}", self.address(), addr);
            event_loop.clear_timeout(timeout);
            return true;
        }
        false
    }
}

impl fmt::Debug for Network {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Network {{ listen_address: {:?}, listener: {:?}, incoming: {:?}, \
        outgoing: {:?}, addresses: {:?}, reconnects: {{ .. }} }}",
            self.listen_address,
            self.listener,
            self.incoming,
            self.outgoing,
            self.addresses
        )
    }
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;
use syn::DeriveInput;

use model::Model;
use util::wrap_in_dummy_mod;

pub fn derive(item: DeriveInput) -> TokenStream {
    let model = Model::from_item(&item, false);

    let struct_name = &item.ident;
    let table_name = model.table_name();

    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
    let mut ref_generics = item.generics.clone();
    ref_generics.params.push(parse_quote!('ident));
    let (ref_generics, ..) = ref_generics.split_for_impl();

    let (field_ty, field_name): (Vec<_>, Vec<_>) = model
        .primary_key_names
        .iter()
        .map(|pk| model.find_column(pk))
        .map(|f| (&f.ty, &f.name))
        .unzip();

    wrap_in_dummy_mod(quote! {
        use diesel::associations::{HasTable, Identifiable};

        impl #impl_generics HasTable for #struct_name #ty_generics
        #where_clause
        {
            type Table = #table_name::table;

            fn table() -> Self::Table {
                #table_name::table
            }
        }

        impl #ref_generics Identifiable for &'ident #struct_name #ty_generics
        #where_clause
        {
            type Id = (#(&'ident #field_ty),*);

            fn id(self) -> Self::Id {
                (#(&self.#field_name),*)
            }
        }

        impl #ref_generics Identifiable for &'ident &'ident #struct_name #ty_generics
            #where_clause
        {
            type Id = (#(&'ident #field_ty),*);

            fn id(self) -> Self::Id {
                (#(&self.#field_name),*)
            }
        }
    })
}
<commit_msg>Address review comment<commit_after>use proc_macro2::TokenStream;
use syn::DeriveInput;

use model::Model;
use util::wrap_in_dummy_mod;

pub fn derive(item: DeriveInput) -> TokenStream {
    let model = Model::from_item(&item, false);

    let struct_name = &item.ident;
    let table_name = model.table_name();

    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
    let mut ref_generics = item.generics.clone();
    ref_generics.params.push(parse_quote!('ident));
    let (ref_generics, ..) = ref_generics.split_for_impl();

    let (field_ty, field_name): (Vec<_>, Vec<_>) = model
        .primary_key_names
        .iter()
        .map(|pk| model.find_column(pk))
        .map(|f| (&f.ty, &f.name))
        .unzip();

    wrap_in_dummy_mod(quote! {
        use diesel::associations::{HasTable, Identifiable};

        impl #impl_generics HasTable for #struct_name #ty_generics
        #where_clause
        {
            type Table = #table_name::table;

            fn table() -> Self::Table {
                #table_name::table
            }
        }

        impl #ref_generics Identifiable for &'ident #struct_name #ty_generics
        #where_clause
        {
            type Id = (#(&'ident #field_ty),*);

            fn id(self) -> Self::Id {
                (#(&self.#field_name),*)
            }
        }

        impl #ref_generics Identifiable for &'_ &'ident #struct_name #ty_generics
            #where_clause
        {
            type Id = (#(&'ident #field_ty),*);

            fn id(self) -> Self::Id {
                (#(&self.#field_name),*)
            }
        }
    })
}
<|endoftext|>


<commit_before>use serde_json::*;

use super::super::lex::*;

///
/// Creates a lexing tool for the scripting language
///
pub fn create_lex_script_tool() -> StringLexingTool {
    // Parse the lexer
    let script_json = from_str::<Vec<LexToolSymbol>>(include_str!("syntax_lexer.json")).unwrap();

    // The name isn't used here, but define it anyway
    let lex_defn = LexToolInput {
        new_tool_name:  String::from("lex-script"),
        symbols:        script_json
    };

    // Create the lexing tool with this definition
    StringLexingTool::from_lex_tool_input(&lex_defn)
}

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

    #[test]
    fn can_parse_syntax_json() {
        let script_json = from_str::<Value>(include_str!("syntax_lexer.json"));

        if script_json.is_err() {
            println!("{:?}", script_json);
            println!("{:?}", script_json.unwrap_err().description());

            assert!(false);
        }
    }

    #[test]
    fn json_can_be_deserialized() {
        let script_json = from_str::<Vec<LexToolSymbol>>(include_str!("syntax_lexer.json"));

        if script_json.is_err() {
            println!("{:?}", script_json);
        }

        script_json.unwrap();
    }

    #[test]
    fn can_create_tool() {
        let _tool = create_lex_script_tool();
    }
}<commit_msg>Add a bunch of tests for the lexer<commit_after>use serde_json::*;

use super::super::lex::*;

///
/// Creates a lexing tool for the scripting language
///
pub fn create_lex_script_tool() -> StringLexingTool {
    // Parse the lexer
    let script_json = from_str::<Vec<LexToolSymbol>>(include_str!("syntax_lexer.json")).unwrap();

    // The name isn't used here, but define it anyway
    let lex_defn = LexToolInput {
        new_tool_name:  String::from("lex-script"),
        symbols:        script_json
    };

    // Create the lexing tool with this definition
    StringLexingTool::from_lex_tool_input(&lex_defn)
}

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

    fn lex_tokens(input: &str) -> Vec<String> {
        let lex_tool = create_lex_script_tool();

        lex_tool
            .lex(input)
            .iter()
            .map(|x| x.token.clone())
            .collect()
    }

    #[test]
    fn can_parse_syntax_json() {
        let script_json = from_str::<Value>(include_str!("syntax_lexer.json"));

        if script_json.is_err() {
            println!("{:?}", script_json);
            println!("{:?}", script_json.unwrap_err().description());

            assert!(false);
        }
    }

    #[test]
    fn json_can_be_deserialized() {
        let script_json = from_str::<Vec<LexToolSymbol>>(include_str!("syntax_lexer.json"));

        if script_json.is_err() {
            println!("{:?}", script_json);
        }

        script_json.unwrap();
    }

    #[test]
    fn can_create_tool() {
        let _tool = create_lex_script_tool();
    }

    #[test]
    fn can_lex_identifier() {
        assert!(lex_tokens("something") == vec![ String::from("Identifier") ]);
    }

    #[test]
    fn can_lex_let_keyword() {
        assert!(lex_tokens("let") == vec![ String::from("let") ]);
    }

    #[test]
    fn can_lex_whitespace() {
        assert!(lex_tokens(" ") == vec![ String::from("Whitespace") ]);
    }

    #[test]
    fn can_lex_plus_symbol() {
        assert!(lex_tokens("+") == vec![ String::from("+") ]);
    }

    #[test]
    fn can_lex_dot_symbol() {
        assert!(lex_tokens(".") == vec![ String::from(".") ]);
    }

    #[test]
    fn can_lex_newline() {
        assert!(lex_tokens("\n") == vec![ String::from("Newline") ]);
    }

    #[test]
    fn can_lex_simple_number() {
        assert!(lex_tokens("1") == vec![ String::from("Number") ]);
    }

    #[test]
    fn can_lex_longer_number() {
        assert!(lex_tokens("123") == vec![ String::from("Number") ]);
    }

    #[test]
    fn can_lex_decimal_number() {
        assert!(lex_tokens("1.21") == vec![ String::from("Number") ]);
    }

    #[test]
    fn can_lex_decimal_with_exponent() {
        assert!(lex_tokens("1.2e10") == vec![ String::from("Number") ]);
    }

    #[test]
    fn can_lex_integer_with_exponent() {
        assert!(lex_tokens("1e10") == vec![ String::from("Number") ]);
    }

    #[test]
    fn can_lex_decimal_number_beginning_with_dot() {
        assert!(lex_tokens(".21") == vec![ String::from("Number") ]);
    }
}
<|endoftext|>