<commit_before>#[doc = "Random number generation"]

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_new() -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;

    #[doc = "Return the next random float"]
    fn next_float() -> float;

    #[doc = "Return a random string composed of A-Z, a-z, 0-9."]
    fn gen_str(len: uint) -> str;

    #[doc = "Return a random byte string."]
    fn gen_bytes(len: uint) -> [u8];
}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

#[doc = "Create a random number generator"]
fn mk_rng() -> rng {
    impl of rng for @rand_res {
        fn next() -> u32 { ret rustrt::rand_next(**self); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**self) as float;
          let u2 = rustrt::rand_next(**self) as float;
          let u3 = rustrt::rand_next(**self) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let mut s = "";
            let mut i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**self) as uint %
                    str::len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let mut v = [];
            let mut i = 0u;
            while i < len {
                let n = rustrt::rand_next(**self) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    @rand_res(rustrt::rand_new()) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {
        let r1: rand::rng = rand::mk_rng();
        log(debug, r1.next());
        log(debug, r1.next());
        {
            let r2 = rand::mk_rng();
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r2.next());
        }
        log(debug, r1.next());
        log(debug, r1.next());
    }

    #[test]
    fn genstr() {
        let r: rand::rng = rand::mk_rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert(str::len(r.gen_str(10u)) == 10u);
        assert(str::len(r.gen_str(16u)) == 16u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Overhaul constructor naming in libs<commit_after>#[doc = "Random number generation"]

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_new() -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;

    #[doc = "Return the next random float"]
    fn next_float() -> float;

    #[doc = "Return a random string composed of A-Z, a-z, 0-9."]
    fn gen_str(len: uint) -> str;

    #[doc = "Return a random byte string."]
    fn gen_bytes(len: uint) -> [u8];
}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

#[doc = "Create a random number generator"]
fn rng() -> rng {
    impl of rng for @rand_res {
        fn next() -> u32 { ret rustrt::rand_next(**self); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**self) as float;
          let u2 = rustrt::rand_next(**self) as float;
          let u3 = rustrt::rand_next(**self) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let mut s = "";
            let mut i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**self) as uint %
                    str::len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let mut v = [];
            let mut i = 0u;
            while i < len {
                let n = rustrt::rand_next(**self) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    @rand_res(rustrt::rand_new()) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {
        let r1: rand::rng = rand::rng();
        log(debug, r1.next());
        log(debug, r1.next());
        {
            let r2 = rand::rng();
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r2.next());
        }
        log(debug, r1.next());
        log(debug, r1.next());
    }

    #[test]
    fn genstr() {
        let r: rand::rng = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert(str::len(r.gen_str(10u)) == 10u);
        assert(str::len(r.gen_str(16u)) == 16u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>//! Utilities that leverage libuv's `uv_timer_*` API

#[forbid(deprecated_mode)];

use uv = uv;
use uv::iotask;
use iotask::IoTask;
use comm = core::comm;

/**
 * Wait for timeout period then send provided value over a channel
 *
 * This call returns immediately. Useful as the building block for a number
 * of higher-level timer functions.
 *
 * Is not guaranteed to wait for exactly the specified time, but will wait
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
 * * msecs - a timeout period, in milliseconds, to wait
 * * ch - a channel of type T to send a `val` on
 * * val - a value of type T to send over the provided `ch`
 */
pub fn delayed_send<T: Copy Send>(iotask: IoTask,
                                  msecs: uint, ch: comm::Chan<T>, val: T) {
        unsafe {
            let timer_done_po = core::comm::Port::<()>();
            let timer_done_ch = core::comm::Chan(&timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(&timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(&timer);
            do iotask::interact(iotask) |loop_ptr| unsafe {
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail ~"timer::delayed_send() start failed: " +
                            error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail ~"timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            core::comm::recv(timer_done_po);
            // notify the caller immediately
            core::comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            core::comm::recv(timer_done_po);
    };
}

/**
 * Blocks the current task for (at least) the specified time period.
 *
 * Is not guaranteed to sleep for exactly the specified time, but will sleep
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `iotask` - a `uv::iotask` that the tcp request will run on
 * * msecs - an amount of time, in milliseconds, for the current task to block
 */
pub fn sleep(iotask: IoTask, msecs: uint) {
    let exit_po = core::comm::Port::<()>();
    let exit_ch = core::comm::Chan(&exit_po);
    delayed_send(iotask, msecs, exit_ch, ());
    core::comm::recv(exit_po);
}

/**
 * Receive on a port for (up to) a specified time, then return an `option<T>`
 *
 * This call will block to receive on the provided port for up to the
 * specified timeout. Depending on whether the provided port receives in that
 * time period, `recv_timeout` will return an `option<T>` representing the
 * result.
 *
 * # Arguments
 *
 * * `iotask' - `uv::iotask` that the tcp request will run on
 * * msecs - an mount of time, in milliseconds, to wait to receive
 * * wait_port - a `core::comm::port<T>` to receive on
 *
 * # Returns
 *
 * An `option<T>` representing the outcome of the call. If the call `recv`'d
 * on the provided port in the allotted timeout period, then the result will
 * be a `some(T)`. If not, then `none` will be returned.
 */
pub fn recv_timeout<T: Copy Send>(iotask: IoTask,
                              msecs: uint,
                              wait_po: comm::Port<T>) -> Option<T> {
    let timeout_po = comm::Port::<()>();
    let timeout_ch = comm::Chan(&timeout_po);
    delayed_send(iotask, msecs, timeout_ch, ());
    // FIXME: This could be written clearer (#2618)
    either::either(
        |left_val| {
            log(debug, fmt!("recv_time .. left_val %?",
                           left_val));
            None
        }, |right_val| {
            Some(*right_val)
        }, &core::comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, fmt!("delayed_send_cb handle %? status %?", handle, status));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        core::comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail ~"timer::sleep() init failed: "+error_msg;
    }
}

extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, fmt!("delayed_send_close_cb handle %?", handle));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[legacy_exports];
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        let hl_loop = uv::global_loop::get();
        sleep(hl_loop, 1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        let hl_loop = uv::global_loop::get();
        for iter::repeat(50u) {
            sleep(hl_loop, 1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = core::comm::Port();
        let ch = core::comm::Chan(&po);
        let hl_loop = uv::global_loop::get();

        let repeat = 20u;
        let spec = {

            ~[(1u,  20u),
             (10u, 10u),
             (20u, 2u)]

        };

        for iter::repeat(repeat) {

            for spec.each |spec| {
                let (times, maxms) = *spec;
                do task::spawn {
                    use rand::*;
                    let rng = Rng();
                    for iter::repeat(times) {
                        sleep(hl_loop, rng.next() as uint % maxms);
                    }
                    core::comm::send(ch, ());
                }
            }
        }

        for iter::repeat(repeat * spec.len()) {
            core::comm::recv(po)
        }
    }

    // Because valgrind serializes multithreaded programs it can
    // make timing-sensitive tests fail in wierd ways. In these
    // next test we run them many times and expect them to pass
    // the majority of tries.

    #[test]
    #[cfg(ignore)]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            task::yield();

            let expected = rand::rng().gen_str(16u);
            let test_po = core::comm::port::<str>();
            let test_ch = core::comm::chan(test_po);

            do task::spawn() {
                delayed_send(hl_loop, 1u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 10u, test_po) {
              some(val) => {
                assert val == expected;
                successes += 1;
              }
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            let expected = rand::Rng().gen_str(16u);
            let test_po = core::comm::Port::<~str>();
            let test_ch = core::comm::Chan(&test_po);

            do task::spawn() {
                delayed_send(hl_loop, 50u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 1u, test_po) {
              None => successes += 1,
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }
}
<commit_msg>Remove Copy bound from std::timer::delayed_send<commit_after>//! Utilities that leverage libuv's `uv_timer_*` API

#[forbid(deprecated_mode)];

use uv = uv;
use uv::iotask;
use iotask::IoTask;
use comm = core::comm;

/**
 * Wait for timeout period then send provided value over a channel
 *
 * This call returns immediately. Useful as the building block for a number
 * of higher-level timer functions.
 *
 * Is not guaranteed to wait for exactly the specified time, but will wait
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
 * * msecs - a timeout period, in milliseconds, to wait
 * * ch - a channel of type T to send a `val` on
 * * val - a value of type T to send over the provided `ch`
 */
pub fn delayed_send<T: Send>(iotask: IoTask,
                                  msecs: uint, ch: comm::Chan<T>, val: T) {
        unsafe {
            let timer_done_po = core::comm::Port::<()>();
            let timer_done_ch = core::comm::Chan(&timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(&timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(&timer);
            do iotask::interact(iotask) |loop_ptr| unsafe {
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail ~"timer::delayed_send() start failed: " +
                            error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail ~"timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            core::comm::recv(timer_done_po);
            // notify the caller immediately
            core::comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            core::comm::recv(timer_done_po);
    };
}

/**
 * Blocks the current task for (at least) the specified time period.
 *
 * Is not guaranteed to sleep for exactly the specified time, but will sleep
 * for *at least* that period of time.
 *
 * # Arguments
 *
 * * `iotask` - a `uv::iotask` that the tcp request will run on
 * * msecs - an amount of time, in milliseconds, for the current task to block
 */
pub fn sleep(iotask: IoTask, msecs: uint) {
    let exit_po = core::comm::Port::<()>();
    let exit_ch = core::comm::Chan(&exit_po);
    delayed_send(iotask, msecs, exit_ch, ());
    core::comm::recv(exit_po);
}

/**
 * Receive on a port for (up to) a specified time, then return an `option<T>`
 *
 * This call will block to receive on the provided port for up to the
 * specified timeout. Depending on whether the provided port receives in that
 * time period, `recv_timeout` will return an `option<T>` representing the
 * result.
 *
 * # Arguments
 *
 * * `iotask' - `uv::iotask` that the tcp request will run on
 * * msecs - an mount of time, in milliseconds, to wait to receive
 * * wait_port - a `core::comm::port<T>` to receive on
 *
 * # Returns
 *
 * An `option<T>` representing the outcome of the call. If the call `recv`'d
 * on the provided port in the allotted timeout period, then the result will
 * be a `some(T)`. If not, then `none` will be returned.
 */
pub fn recv_timeout<T: Copy Send>(iotask: IoTask,
                              msecs: uint,
                              wait_po: comm::Port<T>) -> Option<T> {
    let timeout_po = comm::Port::<()>();
    let timeout_ch = comm::Chan(&timeout_po);
    delayed_send(iotask, msecs, timeout_ch, ());
    // FIXME: This could be written clearer (#2618)
    either::either(
        |left_val| {
            log(debug, fmt!("recv_time .. left_val %?",
                           left_val));
            None
        }, |right_val| {
            Some(*right_val)
        }, &core::comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, fmt!("delayed_send_cb handle %? status %?", handle, status));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        core::comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail ~"timer::sleep() init failed: "+error_msg;
    }
}

extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, fmt!("delayed_send_close_cb handle %?", handle));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::Chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[legacy_exports];
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        let hl_loop = uv::global_loop::get();
        sleep(hl_loop, 1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        let hl_loop = uv::global_loop::get();
        for iter::repeat(50u) {
            sleep(hl_loop, 1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = core::comm::Port();
        let ch = core::comm::Chan(&po);
        let hl_loop = uv::global_loop::get();

        let repeat = 20u;
        let spec = {

            ~[(1u,  20u),
             (10u, 10u),
             (20u, 2u)]

        };

        for iter::repeat(repeat) {

            for spec.each |spec| {
                let (times, maxms) = *spec;
                do task::spawn {
                    use rand::*;
                    let rng = Rng();
                    for iter::repeat(times) {
                        sleep(hl_loop, rng.next() as uint % maxms);
                    }
                    core::comm::send(ch, ());
                }
            }
        }

        for iter::repeat(repeat * spec.len()) {
            core::comm::recv(po)
        }
    }

    // Because valgrind serializes multithreaded programs it can
    // make timing-sensitive tests fail in wierd ways. In these
    // next test we run them many times and expect them to pass
    // the majority of tries.

    #[test]
    #[cfg(ignore)]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            task::yield();

            let expected = rand::rng().gen_str(16u);
            let test_po = core::comm::port::<str>();
            let test_ch = core::comm::chan(test_po);

            do task::spawn() {
                delayed_send(hl_loop, 1u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 10u, test_po) {
              some(val) => {
                assert val == expected;
                successes += 1;
              }
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        for iter::repeat(times as uint) {
            let expected = rand::Rng().gen_str(16u);
            let test_po = core::comm::Port::<~str>();
            let test_ch = core::comm::Chan(&test_po);

            do task::spawn() {
                delayed_send(hl_loop, 50u, test_ch, expected);
            };

            match recv_timeout(hl_loop, 1u, test_po) {
              None => successes += 1,
              _ => failures += 1
            };
        }

        assert successes > times / 2;
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use sys::component::Component;
use sys::processor::*;
use sys::process::*;
use std::fs::{File, read_link};
use std::io::Read;
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{stat, lstat, c_char, sysconf, _SC_CLK_TCK, _SC_PAGESIZE, S_IFLNK, S_IFMT};

pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
}

impl System {
    pub fn new() -> System {
        let mut s = System {
            process_list: HashMap::new(),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: Component::get_components(),
        };
        s.refresh_all();
        s
    }

    pub fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo");
        let lines: Vec<&str> = data.split('\n').collect();

        for component in self.temperatures.iter_mut() {
            component.update();
        }
        for line in lines.iter() {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemAvailable:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat");
        let lines: Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.len() == 0;
        for line in lines.iter() {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _): (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| s.len() > 0);
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(self.processors.get_mut(i).unwrap(),
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    pub fn refresh_process(&mut self) {
        match fs::read_dir(&Path::new("/proc")) {
            Ok(d) => {
                for entry in d {
                    if !entry.is_ok() {
                        continue;
                    }
                    let entry = entry.unwrap();
                    let entry = entry.path();

                    if entry.is_dir() {
                        _get_process_data(entry.as_path(), &mut self.process_list, self.page_size_kb);
                    }
                }
                self.clear_procs();
            }
            Err(_) => {}
        }
    }

    fn clear_procs(&mut self) {
        if self.processors.len() > 0 {
            let (new, old) = get_raw_times(&self.processors[0]);
            let total_time = (new - old) as f32;
            let mut to_delete = Vec::new();
            let nb_processors = self.processors.len() as u64 - 1;

            for (pid, proc_) in self.process_list.iter_mut() {
                if has_been_updated(&proc_) == false {
                    to_delete.push(*pid);
                } else {
                    compute_cpu_usage(proc_, nb_processors, total_time);
                }
            }
            for pid in to_delete {
                self.process_list.remove(&pid);
            }
        }
    }

    // COMMON PART
    //
    // Need to be moved into a "common" file to avoid duplication.

    pub fn refresh_all(&mut self) {
        self.refresh_system();
        self.refresh_process();
    }

    pub fn get_process_list<'a>(&'a self) -> &'a HashMap<usize, Process> {
        &self.process_list
    }

    /// Return the process corresponding to the given pid or None if no such process exists.
    pub fn get_process(&self, pid: i64) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    /// Return a list of process starting with the given name.
    pub fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec!();
        for val in self.process_list.values() {
            if val.name.starts_with(name) {
                ret.push(val);
            }
        }
        ret
    }

    /// The first process in the array is the "main" process
    pub fn get_processor_list<'a>(&'a self) -> &'a [Processor] {
        &self.processors[..]
    }

    pub fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    pub fn get_free_memory(&self) -> u64 {
        self.mem_free
    }

    pub fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_free
    }

    pub fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    pub fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    // need to be checked
    pub fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    pub fn get_components_list<'a>(&'a self) -> &'a [Component] {
        &self.temperatures[..]
    }
}

fn get_all_data(file_path: &str) -> String {
    let mut file = File::open(file_path).unwrap();
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    data
}

fn update_time_and_memory(entry: &mut Process, parts: &[&str], page_size_kb: u64) {
    //entry.name = parts[1][1..].to_owned();
    //entry.name.pop();
    // we get the rss then we add the vsize
    entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb +
                   u64::from_str(parts[22]).unwrap() / 1024;
    set_time(entry,
             u64::from_str(parts[13]).unwrap(),
             u64::from_str(parts[14]).unwrap());
}

fn _get_process_data(path: &Path, proc_list: &mut HashMap<usize, Process>, page_size_kb: u64) {
    if !path.exists() || !path.is_dir() {
        return;
    }
    let paths : Vec<&str> = path.as_os_str().to_str().unwrap().split("/").collect();
    let last = paths[paths.len() - 1];
    match i64::from_str(last) {
        Ok(nb) => {
            let mut tmp = PathBuf::from(path);

            tmp.push("stat");
            let data = get_all_data(tmp.to_str().unwrap());
            let (parts, _): (Vec<&str>, Vec<&str>) = data.split(' ').partition(|s| s.len() > 0);
            if let Some(ref mut entry) = proc_list.get_mut(&(nb as usize)) {
                update_time_and_memory(entry, &parts, page_size_kb);
                return;
            }

            let parent = match i64::from_str(parts[3]).unwrap() {
                0 => None,
                p => Some(p)
            };

            let mut p = Process::new(nb,
                                     parent,
                                     u64::from_str(parts[21]).unwrap() /
                                     unsafe { sysconf(_SC_CLK_TCK) } as u64);

            tmp = PathBuf::from(path);
            tmp.push("cmdline");
            p.cmd = if let Some(t) = copy_from_file(&tmp).get(0) {
                t.clone()
            } else {
                String::new()
            };
            let x = p.cmd.split(":").collect::<Vec<&str>>()[0]
                         .split(" ").collect::<Vec<&str>>()[0].to_owned();
            p.name = if x.contains("/") {
                x.split("/").last().unwrap().to_owned()
            } else {
                x
            };
            tmp = PathBuf::from(path);
            tmp.push("environ");
            p.environ = copy_from_file(&tmp);
            tmp = PathBuf::from(path);
            tmp.push("exe");

            let s = read_link(tmp.to_str().unwrap());

            if s.is_ok() {
                p.exe = s.unwrap().to_str().unwrap().to_owned();
            }
            tmp = PathBuf::from(path);
            tmp.push("cwd");
            p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("root");
            p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();

            update_time_and_memory(&mut p, &parts, page_size_kb);
            proc_list.insert(nb as usize, p);
        }
        _ => {}
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            let v : Vec<&str> = d.split('\0').collect();
            let mut ret : Vec<String> = Vec::new();

            for tmp in v.iter() {
            if tmp.len() < 1 {
                    continue;
                }
                ret.push((*tmp).to_owned());
            }
            ret
        },
        Err(_) => Vec::new()
    }
}

fn realpath(original: &Path) -> PathBuf {
    let ori = Path::new(original.to_str().unwrap());

    // Right now lstat on windows doesn't work quite well
    if cfg!(windows) {
        return PathBuf::from(ori);
    }
    let result = PathBuf::from(original);
    let mut buf: stat = unsafe { ::std::mem::uninitialized() };
    let res = unsafe { lstat(result.to_str().unwrap().as_ptr() as *const c_char, &mut buf as *mut stat) };
    if res < 0 || (buf.st_mode & S_IFMT) != S_IFLNK {
        PathBuf::new()
    } else {
        match fs::read_link(&result) {
            Ok(f) => f,
        Err(_) => PathBuf::new(),
        }
    }
}
<commit_msg>Remove ":" command splitting in linux<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use sys::component::Component;
use sys::processor::*;
use sys::process::*;
use std::fs::{File, read_link};
use std::io::Read;
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{stat, lstat, c_char, sysconf, _SC_CLK_TCK, _SC_PAGESIZE, S_IFLNK, S_IFMT};

pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
}

impl System {
    pub fn new() -> System {
        let mut s = System {
            process_list: HashMap::new(),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: Component::get_components(),
        };
        s.refresh_all();
        s
    }

    pub fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo");
        let lines: Vec<&str> = data.split('\n').collect();

        for component in self.temperatures.iter_mut() {
            component.update();
        }
        for line in lines.iter() {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemAvailable:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat");
        let lines: Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.len() == 0;
        for line in lines.iter() {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _): (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| s.len() > 0);
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(self.processors.get_mut(i).unwrap(),
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    pub fn refresh_process(&mut self) {
        match fs::read_dir(&Path::new("/proc")) {
            Ok(d) => {
                for entry in d {
                    if !entry.is_ok() {
                        continue;
                    }
                    let entry = entry.unwrap();
                    let entry = entry.path();

                    if entry.is_dir() {
                        _get_process_data(entry.as_path(), &mut self.process_list, self.page_size_kb);
                    }
                }
                self.clear_procs();
            }
            Err(_) => {}
        }
    }

    fn clear_procs(&mut self) {
        if self.processors.len() > 0 {
            let (new, old) = get_raw_times(&self.processors[0]);
            let total_time = (new - old) as f32;
            let mut to_delete = Vec::new();
            let nb_processors = self.processors.len() as u64 - 1;

            for (pid, proc_) in self.process_list.iter_mut() {
                if has_been_updated(&proc_) == false {
                    to_delete.push(*pid);
                } else {
                    compute_cpu_usage(proc_, nb_processors, total_time);
                }
            }
            for pid in to_delete {
                self.process_list.remove(&pid);
            }
        }
    }

    // COMMON PART
    //
    // Need to be moved into a "common" file to avoid duplication.

    pub fn refresh_all(&mut self) {
        self.refresh_system();
        self.refresh_process();
    }

    pub fn get_process_list<'a>(&'a self) -> &'a HashMap<usize, Process> {
        &self.process_list
    }

    /// Return the process corresponding to the given pid or None if no such process exists.
    pub fn get_process(&self, pid: i64) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    /// Return a list of process starting with the given name.
    pub fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec!();
        for val in self.process_list.values() {
            if val.name.starts_with(name) {
                ret.push(val);
            }
        }
        ret
    }

    /// The first process in the array is the "main" process
    pub fn get_processor_list<'a>(&'a self) -> &'a [Processor] {
        &self.processors[..]
    }

    pub fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    pub fn get_free_memory(&self) -> u64 {
        self.mem_free
    }

    pub fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_free
    }

    pub fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    pub fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    // need to be checked
    pub fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    pub fn get_components_list<'a>(&'a self) -> &'a [Component] {
        &self.temperatures[..]
    }
}

fn get_all_data(file_path: &str) -> String {
    let mut file = File::open(file_path).unwrap();
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    data
}

fn update_time_and_memory(entry: &mut Process, parts: &[&str], page_size_kb: u64) {
    //entry.name = parts[1][1..].to_owned();
    //entry.name.pop();
    // we get the rss then we add the vsize
    entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb +
                   u64::from_str(parts[22]).unwrap() / 1024;
    set_time(entry,
             u64::from_str(parts[13]).unwrap(),
             u64::from_str(parts[14]).unwrap());
}

fn _get_process_data(path: &Path, proc_list: &mut HashMap<usize, Process>, page_size_kb: u64) {
    if !path.exists() || !path.is_dir() {
        return;
    }
    let paths : Vec<&str> = path.as_os_str().to_str().unwrap().split("/").collect();
    let last = paths[paths.len() - 1];
    match i64::from_str(last) {
        Ok(nb) => {
            let mut tmp = PathBuf::from(path);

            tmp.push("stat");
            let data = get_all_data(tmp.to_str().unwrap());
            let (parts, _): (Vec<&str>, Vec<&str>) = data.split(' ').partition(|s| s.len() > 0);
            if let Some(ref mut entry) = proc_list.get_mut(&(nb as usize)) {
                update_time_and_memory(entry, &parts, page_size_kb);
                return;
            }

            let parent = match i64::from_str(parts[3]).unwrap() {
                0 => None,
                p => Some(p)
            };

            let mut p = Process::new(nb,
                                     parent,
                                     u64::from_str(parts[21]).unwrap() /
                                     unsafe { sysconf(_SC_CLK_TCK) } as u64);

            tmp = PathBuf::from(path);
            tmp.push("cmdline");
            p.cmd = if let Some(t) = copy_from_file(&tmp).get(0) {
                t.clone()
            } else {
                String::new()
            };
            let x = p.cmd.split(" ").collect::<Vec<&str>>()[0].to_owned();
            p.name = if x.contains("/") {
                x.split("/").last().unwrap().to_owned()
            } else {
                x
            };
            tmp = PathBuf::from(path);
            tmp.push("environ");
            p.environ = copy_from_file(&tmp);
            tmp = PathBuf::from(path);
            tmp.push("exe");

            let s = read_link(tmp.to_str().unwrap());

            if s.is_ok() {
                p.exe = s.unwrap().to_str().unwrap().to_owned();
            }
            tmp = PathBuf::from(path);
            tmp.push("cwd");
            p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("root");
            p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();

            update_time_and_memory(&mut p, &parts, page_size_kb);
            proc_list.insert(nb as usize, p);
        }
        _ => {}
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            let v : Vec<&str> = d.split('\0').collect();
            let mut ret : Vec<String> = Vec::new();

            for tmp in v.iter() {
            if tmp.len() < 1 {
                    continue;
                }
                ret.push((*tmp).to_owned());
            }
            ret
        },
        Err(_) => Vec::new()
    }
}

fn realpath(original: &Path) -> PathBuf {
    let ori = Path::new(original.to_str().unwrap());

    // Right now lstat on windows doesn't work quite well
    if cfg!(windows) {
        return PathBuf::from(ori);
    }
    let result = PathBuf::from(original);
    let mut buf: stat = unsafe { ::std::mem::uninitialized() };
    let res = unsafe { lstat(result.to_str().unwrap().as_ptr() as *const c_char, &mut buf as *mut stat) };
    if res < 0 || (buf.st_mode & S_IFMT) != S_IFLNK {
        PathBuf::new()
    } else {
        match fs::read_link(&result) {
            Ok(f) => f,
        Err(_) => PathBuf::new(),
        }
    }
}
<|endoftext|>


<commit_before>use rand::Rng;

use geometry::Size;
use models::{Bullet, Enemy, Particle, Player, Star};

const MAX_STARS: usize = 100;

/// A model that contains the other models and renders them
pub struct World {
    pub player: Player,
    pub particles: Vec<Particle>,
    pub bullets: Vec<Bullet>,
    pub enemies: Vec<Enemy>,
    pub stars: Vec<Star>,
    pub size: Size
}

impl World {
    /// Returns a new world of the given size
    pub fn new<R: Rng>(rng: &mut R, size: Size) -> World {

        // Add stars up to MAX_STARS
        let mut stars = vec![];
        while stars.len() < MAX_STARS {
            stars.push(Star::new(size));
        }

        World {
            player: Player::random(rng, size),
            particles: Vec::with_capacity(1000),
            bullets: vec![],
            enemies: vec![],
            stars: stars,
            size: size
        }
    }
}
<commit_msg>Style<commit_after>use rand::Rng;

use geometry::Size;
use models::{Bullet, Enemy, Particle, Player, Star};

const MAX_STARS: usize = 100;

/// A model that contains the other models and renders them
pub struct World {
    pub player: Player,
    pub particles: Vec<Particle>,
    pub bullets: Vec<Bullet>,
    pub enemies: Vec<Enemy>,
    pub stars: Vec<Star>,
    pub size: Size
}

impl World {
    /// Returns a new world of the given size
    pub fn new<R: Rng>(rng: &mut R, size: Size) -> World {
        World {
            player: Player::random(rng, size),
            particles: Vec::with_capacity(1000),
            bullets: vec![],
            enemies: vec![],
            stars: (0..MAX_STARS).map(|_| Star::new(size)).collect(),
            size: size
        }
    }
}
<|endoftext|>


<commit_before>//use std::collections::HashMap;
use std::ffi::CString;
use libc::c_int;

use super::ffi;

use {SqliteResult, SqliteError, SqliteConnection, SqliteStatement, SqliteRows, SqliteRow};
use types::ToSql;

impl SqliteConnection {
    /// Convenience method to prepare and execute a single SQL statement with named parameter(s).
    ///
    /// ## Example
    ///
    /// ```rust,no_run
    /// # use rusqlite::{SqliteConnection, SqliteResult};
    /// fn insert(conn: &SqliteConnection) -> SqliteResult<i32> {
    ///   conn.execute_named("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)", &[(":name", &"one")])
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params))
    }

    /// Convenience method to execute a query with named parameter(s) that is expected to return a single row.
    ///
    /// If the query returns more than one row, all rows except the first are ignored.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn query_named_row<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> SqliteResult<T>
                           where F: FnOnce(SqliteRow) -> T {
        let mut stmt = try!(self.prepare(sql));
        let mut rows = try!(stmt.query_named(params));

        match rows.next() {
            Some(row) => row.map(f),
            None      => Err(SqliteError{
                code: ffi::SQLITE_NOTICE,
                message: "Query did not return a row".to_string(),
            })
        }
    }
}

impl<'conn> SqliteStatement<'conn> {
    /*pub fn parameter_names(&self) -> HashMap<String, i32> {
        let n = unsafe { ffi::sqlite3_bind_parameter_count(self.stmt) };
        let mut index_by_name = HashMap::with_capacity(n as usize);
        for i in 1..n+1 {
            let c_name = unsafe { ffi::sqlite3_bind_parameter_name(self.stmt, i) };
            if !c_name.is_null() {
                let c_slice = unsafe { CStr::from_ptr(c_name).to_bytes() };
                index_by_name.insert(str::from_utf8(c_slice).unwrap().to_string(), n);
            }
        }
        index_by_name
    }*/

    /// Return the index of an SQL parameter given its name.
    ///
    /// # Failure
    ///
    /// Return None if `name` is invalid (NulError) or if no matching parameter is found.
    pub fn parameter_index(&self, name: &str) -> Option<i32> {
        unsafe {
            CString::new(name).ok().and_then(|c_name|
                match ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) {
                    0 => None, // A zero is returned if no matching parameter is found.
                    n => Some(n)
                }
            )

        }
    }

    /// Execute the prepared statement with named parameter(s).
    ///
    /// On success, returns the number of rows that were changed or inserted or deleted (via
    /// `sqlite3_changes`).
    ///
    /// ## Example
    ///
    /// ```rust,no_run
    /// # use rusqlite::{SqliteConnection, SqliteResult};
    /// fn insert(conn: &SqliteConnection) -> SqliteResult<i32> {
    ///   let mut stmt = try!(conn.prepare("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)"));
    ///   return stmt.execute_named(&[(":name", &"one")]);
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if binding parameters fails, the executed statement returns rows (in
    /// which case `query` should be used instead), or the underling SQLite call fails.
    pub fn execute_named(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        unsafe {
            try!(self.bind_named_parameters(params));
            self.execute_()
        }
    }

    /// Execute the prepared statement with named parameter(s), returning an iterator over the resulting rows.
    ///
    /// ## Example
    ///
    /// ```rust,no_run
    /// # use rusqlite::{SqliteConnection, SqliteResult, SqliteRows};
    /// fn query(conn: &SqliteConnection) -> SqliteResult<()> {
    ///   let mut stmt = try!(conn.prepare("SELECT * FROM test where name = :name"));
    ///   let mut rows = try!(stmt.query_named(&[(":name", &"one")]));
    ///   for row in rows {
    ///   // ...
    ///   }
    ///   return Ok(())
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if binding parameters fails.
    pub fn query_named<'a>(&'a mut self, params: &[(&str, &ToSql)]) -> SqliteResult<SqliteRows<'a>> {
        self.reset_if_needed();

        unsafe {
            try!(self.bind_named_parameters(params));
        }

        self.needs_reset = true;
        Ok(SqliteRows::new(self))
    }

    unsafe fn bind_named_parameters(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<()> {
        for &(name, value) in params {
            let i = try!(self.parameter_index(name).ok_or(SqliteError{
                code: ffi::SQLITE_MISUSE,
                message: format!("Invalid parameter name: {}", name)
            }));
            try!(self.conn.decode_result(value.bind_parameter(self.stmt, i)));
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;

    #[test]
    fn test_execute_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();

        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(), 1);
        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]).unwrap(), 1);

        assert_eq!(3i32, db.query_named_row("SELECT SUM(x) FROM foo WHERE x > :x", &[(":x", &0i32)], |r| r.get(0)).unwrap());
    }

   #[test]
    fn test_stmt_execute_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)").unwrap();
        stmt.execute_named(&[(":name", &"one")]).unwrap();
    }

   #[test]
    fn test_query_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("SELECT * FROM test where name = :name").unwrap();
        stmt.query_named(&[(":name", &"one")]).unwrap();
    }
}
<commit_msg>Run rustfmt on named_params.rs<commit_after>// use std::collections::HashMap;
use std::ffi::CString;
use libc::c_int;

use super::ffi;

use {SqliteResult, SqliteError, SqliteConnection, SqliteStatement, SqliteRows, SqliteRow};
use types::ToSql;

impl SqliteConnection {
    /// Convenience method to prepare and execute a single SQL statement with named parameter(s).
    ///
    /// ## Example
    ///
    /// ```rust,no_run
    /// # use rusqlite::{SqliteConnection, SqliteResult};
    /// fn insert(conn: &SqliteConnection) -> SqliteResult<i32> {
    ///   conn.execute_named("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)", &[(":name", &"one")])
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params))
    }

    /// Convenience method to execute a query with named parameter(s) that is expected to return a single row.
    ///
    /// If the query returns more than one row, all rows except the first are ignored.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn query_named_row<T, F>(&self,
                                 sql: &str,
                                 params: &[(&str, &ToSql)],
                                 f: F)
                                 -> SqliteResult<T>
        where F: FnOnce(SqliteRow) -> T
    {
        let mut stmt = try!(self.prepare(sql));
        let mut rows = try!(stmt.query_named(params));

        match rows.next() {
            Some(row) => row.map(f),
            None => {
                Err(SqliteError {
                    code: ffi::SQLITE_NOTICE,
                    message: "Query did not return a row".to_string(),
                })
            }
        }
    }
}

impl<'conn> SqliteStatement<'conn> {
    // pub fn parameter_names(&self) -> HashMap<String, i32> {
    // let n = unsafe { ffi::sqlite3_bind_parameter_count(self.stmt) };
    // let mut index_by_name = HashMap::with_capacity(n as usize);
    // for i in 1..n+1 {
    // let c_name = unsafe { ffi::sqlite3_bind_parameter_name(self.stmt, i) };
    // if !c_name.is_null() {
    // let c_slice = unsafe { CStr::from_ptr(c_name).to_bytes() };
    // index_by_name.insert(str::from_utf8(c_slice).unwrap().to_string(), n);
    // }
    // }
    // index_by_name
    // }

    /// Return the index of an SQL parameter given its name.
    ///
    /// # Failure
    ///
    /// Return None if `name` is invalid (NulError) or if no matching parameter is found.
    pub fn parameter_index(&self, name: &str) -> Option<i32> {
        unsafe {
            CString::new(name).ok().and_then(|c_name| {
                match ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) {
                    0 => None, // A zero is returned if no matching parameter is found.
                    n => Some(n),
                }
            })

        }
    }

    /// Execute the prepared statement with named parameter(s).
    ///
    /// On success, returns the number of rows that were changed or inserted or deleted (via
    /// `sqlite3_changes`).
    ///
    /// ## Example
    ///
    /// ```rust,no_run
    /// # use rusqlite::{SqliteConnection, SqliteResult};
    /// fn insert(conn: &SqliteConnection) -> SqliteResult<i32> {
    ///   let mut stmt = try!(conn.prepare("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)"));
    ///   return stmt.execute_named(&[(":name", &"one")]);
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if binding parameters fails, the executed statement returns rows (in
    /// which case `query` should be used instead), or the underling SQLite call fails.
    pub fn execute_named(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        unsafe {
            try!(self.bind_named_parameters(params));
            self.execute_()
        }
    }

    /// Execute the prepared statement with named parameter(s), returning an iterator over the resulting rows.
    ///
    /// ## Example
    ///
    /// ```rust,no_run
    /// # use rusqlite::{SqliteConnection, SqliteResult, SqliteRows};
    /// fn query(conn: &SqliteConnection) -> SqliteResult<()> {
    ///   let mut stmt = try!(conn.prepare("SELECT * FROM test where name = :name"));
    ///   let mut rows = try!(stmt.query_named(&[(":name", &"one")]));
    ///   for row in rows {
    ///   // ...
    ///   }
    ///   return Ok(())
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if binding parameters fails.
    pub fn query_named<'a>(&'a mut self,
                           params: &[(&str, &ToSql)])
                           -> SqliteResult<SqliteRows<'a>> {
        self.reset_if_needed();

        unsafe {
            try!(self.bind_named_parameters(params));
        }

        self.needs_reset = true;
        Ok(SqliteRows::new(self))
    }

    unsafe fn bind_named_parameters(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<()> {
        for &(name, value) in params {
            let i = try!(self.parameter_index(name).ok_or(SqliteError {
                code: ffi::SQLITE_MISUSE,
                message: format!("Invalid parameter name: {}", name),
            }));
            try!(self.conn.decode_result(value.bind_parameter(self.stmt, i)));
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;

    #[test]
    fn test_execute_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();

        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(),
                   1);
        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]).unwrap(),
                   1);

        assert_eq!(3i32,
                   db.query_named_row("SELECT SUM(x) FROM foo WHERE x > :x",
                                      &[(":x", &0i32)],
                                      |r| r.get(0))
                     .unwrap());
    }

    #[test]
    fn test_stmt_execute_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
                   INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)")
                         .unwrap();
        stmt.execute_named(&[(":name", &"one")]).unwrap();
    }

    #[test]
    fn test_query_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
                   INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("SELECT * FROM test where name = :name").unwrap();
        stmt.query_named(&[(":name", &"one")]).unwrap();
    }
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]
use std::collections::HashMap;
use std::boxed::Box;
use std::io::{Read, Write};

use mio::{self, Token, EventLoop, EventSet, PollOpt};
use mio::tcp::TcpListener;
use protobuf::core::Message;
use protobuf::RepeatedField;

use proto::kvrpcpb;
use proto::kvrpcpb::{CmdGetRequest, CmdGetResponse, CmdScanRequest, CmdScanResponse,
                     CmdPrewriteRequest, CmdPrewriteResponse, CmdCommitRequest, CmdCommitResponse,
                     Request, Response, MessageType};
use util;
use util::codec::rpc::{encode_msg, MSG_HEADER_LEN};
use storage;
use storage::{Key, Storage, Value, KvPair};

use super::conn::Conn;

pub type Result<T> = ::std::result::Result<T, ServerError>;

pub const SERVER_TOKEN: Token = Token(0);

quick_error! {
    #[derive(Debug)]
    pub enum ServerError {
        Storage(err: storage::Error) {
            from()
            cause(err)
            description(err.description())
        }
        FormatError(desc: String) {
            description(desc)
        }
    }
}

pub struct Server {
    pub listener: TcpListener,
    pub conns: HashMap<Token, Conn>,
    pub token_counter: usize,
    store: Storage,
}

impl Server {
    pub fn new(listener: TcpListener,
               conns: HashMap<Token, Conn>,
               tc: usize,
               store: Storage)
               -> Server {
        return Server {
            listener: listener,
            conns: conns,
            token_counter: tc,
            store: store,
        };
    }
    pub fn handle_get(&mut self,
                      msg: &Request,
                      msg_id: u64,
                      token: Token,
                      event_loop: &mut EventLoop<Server>)
                      -> Result<()> {
        if !msg.has_cmd_get_req() {
            error!("Msg doesn't containe a CmdGetRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdGetRequest"
                                                    .to_string()));
        }
        let cmd_get_req: &CmdGetRequest = msg.get_cmd_get_req();
        let key = cmd_get_req.get_key().iter().cloned().collect();
        let sender = event_loop.channel();
        match self.store.async_get(key,
                                   cmd_get_req.get_version(),
                                   Box::new(move |v: ::std::result::Result<Option<Value>,
                                                                             storage::Error>| {
                                       let resp: Response = Server::cmd_get_done(v);
                                       let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                       sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                                   })) {
            Ok(()) => Ok(()),
            Err(why) => return Err(ServerError::Storage(why)),
        }
    }
    pub fn handle_scan(&mut self,
                       msg: &Request,
                       msg_id: u64,
                       token: Token,
                       event_loop: &mut EventLoop<Server>)
                       -> Result<()> {
        if !msg.has_cmd_scan_req() {
            error!("Msg doesn't containe a CmdScanRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdScanRequest"
                                                    .to_string()));
        }
        let cmd_scan_req: &CmdScanRequest = msg.get_cmd_scan_req();
        let sender = event_loop.channel();
        // convert [u8] to Vec[u8]
        let start_key: Key = cmd_scan_req.get_key().iter().cloned().collect();
        debug!("start_key [{:?}]", start_key);
        match self.store
                  .async_scan(start_key,
                              cmd_scan_req.get_limit() as usize,
                              cmd_scan_req.get_version(),
                              Box::new(move |kvs: ::std::result::Result<Vec<KvPair>,
                                                                          storage::Error>| {
                                  let resp: Response = Server::cmd_scan_done(kvs);
                                  let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                  sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                              })) {
            Ok(()) => Ok(()),
            Err(why) => return Err(ServerError::Storage(why)),
        }
    }
    pub fn handle_prewrite(&mut self,
                           msg: &Request,
                           msg_id: u64,
                           token: Token,
                           event_loop: &mut EventLoop<Server>)
                           -> Result<()> {
        if !msg.has_cmd_prewrite_req() {
            error!("Msg doesn't containe a CmdPrewriteRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdPrewriteRequest"
                                                    .to_string()));
        }
        let cmd_prewrite_req: &CmdPrewriteRequest = msg.get_cmd_prewrite_req();
        let sender = event_loop.channel();
        let puts: Vec<_> = cmd_prewrite_req.get_puts()
                                           .iter()
                                           .map(|kv| {
                                               (util::array_to_vec(kv.get_key()),
                                                util::array_to_vec(kv.get_value()))
                                           })
                                           .collect();
        let deletes: Vec<_> = cmd_prewrite_req.get_dels().iter().cloned().collect();
        let locks: Vec<_> = cmd_prewrite_req.get_locks().iter().cloned().collect();
        match self.store
                  .async_prewrite(puts,
                                  deletes,
                                  locks,
                                  cmd_prewrite_req.get_start_version(),
                                  Box::new(move |r: ::std::result::Result<(),
                                                                            storage::Error>| {
                                      let resp: Response = Server::cmd_prewrite_done(r);
                                      let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                      sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                                  })) {
            Ok(()) => Ok(()),
            Err(why) => return Err(ServerError::Storage(why)),
        }
    }
    pub fn handle_commit(&mut self,
                         msg: &Request,
                         msg_id: u64,
                         token: Token,
                         event_loop: &mut EventLoop<Server>)
                         -> Result<()> {
        if !msg.has_cmd_commit_req() {
            error!("Msg doesn't containe a CmdCommitRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdCommitRequest"
                                                    .to_string()));
        }
        let cmd_commit_req: &CmdCommitRequest = msg.get_cmd_commit_req();
        let sender = event_loop.channel();
        match self.store
                  .async_commit(cmd_commit_req.get_start_version(),
                                cmd_commit_req.get_commit_version(),
                                Box::new(move |r: ::std::result::Result<(), storage::Error>| {
                                    let resp: Response = Server::cmd_commit_done(r);
                                    let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                    // [TODO]: retry
                                    sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                                })) {
            Ok(()) => Ok(()),
            Err(why) => Err(ServerError::Storage(why)),
        }
    }
    fn cmd_get_done(r: ::std::result::Result<Option<Value>, storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_get_resp: CmdGetResponse = CmdGetResponse::new();
        cmd_get_resp.set_ok(r.is_ok());
        match r {
            Ok(v) => {
                match v {
                    Some(val) => cmd_get_resp.set_value(val),
                    None => cmd_get_resp.set_value(Vec::new()),
                }
                cmd_get_resp.set_ok(true);
            }
            Err(_) => {}
        }
        resp.set_field_type(MessageType::CmdGet);
        resp.set_cmd_get_resp(cmd_get_resp);
        resp
    }
    fn cmd_scan_done(kvs: ::std::result::Result<Vec<KvPair>, storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_scan_resp: CmdScanResponse = CmdScanResponse::new();
        cmd_scan_resp.set_ok(kvs.is_ok());
        match kvs {
            Ok(v) => {
                // convert storage::KvPair to kvrpcpb::KvPair
                let mut new_kvs: Vec<kvrpcpb::KvPair> = Vec::new();
                for x in &v {
                    let mut new_kv: kvrpcpb::KvPair = kvrpcpb::KvPair::new();
                    new_kv.set_key(x.0.clone());
                    new_kv.set_value(x.1.clone());
                    new_kvs.push(new_kv);
                }
                cmd_scan_resp.set_results(RepeatedField::from_vec(new_kvs));
            }
            Err(_) => {}
        }
        resp.set_field_type(MessageType::CmdScan);
        resp.set_cmd_scan_resp(cmd_scan_resp);
        resp
    }
    fn cmd_prewrite_done(r: ::std::result::Result<(), storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_prewrite_resp: CmdPrewriteResponse = CmdPrewriteResponse::new();
        cmd_prewrite_resp.set_ok(r.is_ok());
        resp.set_field_type(MessageType::CmdPrewrite);
        resp.set_cmd_prewrite_resp(cmd_prewrite_resp);
        resp
    }
    fn cmd_commit_done(r: ::std::result::Result<(), storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_commit_resp: CmdCommitResponse = CmdCommitResponse::new();
        cmd_commit_resp.set_ok(r.is_ok());
        resp.set_field_type(MessageType::CmdCommit);
        resp.set_cmd_commit_resp(cmd_commit_resp);
        resp
    }
}

pub enum QueueMessage {
    // Request(token, msg_id, kvrpc_request)
    Request(Token, u64, Request),
    // Request(token, msg_id, kvrpc_response)
    Response(Token, u64, Response),
}

impl mio::Handler for Server {
    type Timeout = ();
    type Message = QueueMessage;

    fn ready(&mut self, event_loop: &mut EventLoop<Server>, token: Token, events: EventSet) {
        if events.is_hup() || events.is_error() {
            self.conns.remove(&token);
            return;
        }

        if events.is_readable() {
            match token {
                SERVER_TOKEN => {
                    let sock = match self.listener.accept() {
                        // Some(sock, addr)
                        Ok(Some((sock, _))) => sock,
                        Ok(None) => unreachable!(),
                        Err(e) => {
                            error!("accept error: {}", e);
                            return;
                        }
                    };

                    let new_token = Token(self.token_counter);
                    match sock.set_nodelay(true) {
                        Ok(_) => {}
                        Err(e) => error!("set nodeplay failed {:?}", e),
                    }
                    self.conns.insert(new_token, Conn::new(sock));
                    self.token_counter += 1;

                    event_loop.register(&self.conns[&new_token].sock,
                                        new_token,
                                        EventSet::readable(),
                                        PollOpt::level() | PollOpt::oneshot())
                              .unwrap();

                }
                token => {
                    let mut conn: &mut Conn = match self.conns.get_mut(&token) {
                        Some(c) => c,
                        None => {
                            error!("Get connection failed token[{}]", token.0);
                            return;
                        }
                    };
                    conn.read(token, event_loop);
                    event_loop.reregister(&conn.sock,
                                          token,
                                          conn.interest,
                                          PollOpt::level() | PollOpt::oneshot())
                              .unwrap();
                }
            }
        }

        if events.is_writable() {
            let mut conn: &mut Conn = match self.conns.get_mut(&token) {
                Some(c) => c,
                None => {
                    error!("Get connection failed token[{}]", token.0);
                    return;
                }
            };
            conn.write();
            event_loop.reregister(&conn.sock,
                                  token,
                                  conn.interest,
                                  PollOpt::level() | PollOpt::oneshot())
                      .unwrap();
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Server>, msg: QueueMessage) {
        match msg {
            QueueMessage::Request(token, msg_id, req) => {
                debug!("notify Request token[{}] msg_id[{}] type[{:?}]",
                       token.0,
                       msg_id,
                       req.get_field_type());
                match req.get_field_type() {
                    MessageType::CmdGet => {
                        if let Err(e) = self.handle_get(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        };
                    }
                    MessageType::CmdScan => {
                        if let Err(e) = self.handle_scan(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        }
                    }
                    MessageType::CmdPrewrite => {
                        if let Err(e) = self.handle_prewrite(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        }
                    }
                    MessageType::CmdCommit => {
                        if let Err(e) = self.handle_commit(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        }
                    }
                }
            }
            QueueMessage::Response(token, msg_id, resp) => {
                debug!("notify Response token[{}] msg_id[{}] type[{:?}]",
                       token.0,
                       msg_id,
                       resp.get_field_type());
                let mut conn: &mut Conn = match self.conns.get_mut(&token) {
                    Some(c) => c,
                    None => {
                        error!("Get connection failed token[{}]", token.0);
                        return;
                    }
                };
                conn.res.clear();
                let resp_len: usize = MSG_HEADER_LEN + resp.compute_size() as usize;
                if conn.res.capacity() < resp_len {
                    conn.res = Vec::with_capacity(resp_len);
                }
                encode_msg(&mut conn.res, msg_id, &resp).unwrap();
                conn.interest.insert(EventSet::writable());
                event_loop.reregister(&conn.sock,
                                      token,
                                      conn.interest,
                                      PollOpt::level() | PollOpt::oneshot())
                          .unwrap();
            }
        }
    }
}
<commit_msg>kvrpc: add Quit to QueueMessage<commit_after>#![allow(unused_must_use)]
use std::collections::HashMap;
use std::boxed::Box;
use std::io::{Read, Write};

use mio::{self, Token, EventLoop, EventSet, PollOpt};
use mio::tcp::TcpListener;
use protobuf::core::Message;
use protobuf::RepeatedField;

use proto::kvrpcpb;
use proto::kvrpcpb::{CmdGetRequest, CmdGetResponse, CmdScanRequest, CmdScanResponse,
                     CmdPrewriteRequest, CmdPrewriteResponse, CmdCommitRequest, CmdCommitResponse,
                     Request, Response, MessageType};
use util;
use util::codec::rpc::{encode_msg, MSG_HEADER_LEN};
use storage;
use storage::{Key, Storage, Value, KvPair};

use super::conn::Conn;

pub type Result<T> = ::std::result::Result<T, ServerError>;

pub const SERVER_TOKEN: Token = Token(0);

quick_error! {
    #[derive(Debug)]
    pub enum ServerError {
        Storage(err: storage::Error) {
            from()
            cause(err)
            description(err.description())
        }
        FormatError(desc: String) {
            description(desc)
        }
    }
}

pub struct Server {
    pub listener: TcpListener,
    pub conns: HashMap<Token, Conn>,
    pub token_counter: usize,
    store: Storage,
}

impl Server {
    pub fn new(listener: TcpListener,
               conns: HashMap<Token, Conn>,
               tc: usize,
               store: Storage)
               -> Server {
        return Server {
            listener: listener,
            conns: conns,
            token_counter: tc,
            store: store,
        };
    }
    pub fn handle_get(&mut self,
                      msg: &Request,
                      msg_id: u64,
                      token: Token,
                      event_loop: &mut EventLoop<Server>)
                      -> Result<()> {
        if !msg.has_cmd_get_req() {
            error!("Msg doesn't containe a CmdGetRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdGetRequest"
                                                    .to_string()));
        }
        let cmd_get_req: &CmdGetRequest = msg.get_cmd_get_req();
        let key = cmd_get_req.get_key().iter().cloned().collect();
        let sender = event_loop.channel();
        match self.store.async_get(key,
                                   cmd_get_req.get_version(),
                                   Box::new(move |v: ::std::result::Result<Option<Value>,
                                                                             storage::Error>| {
                                       let resp: Response = Server::cmd_get_done(v);
                                       let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                       sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                                   })) {
            Ok(()) => Ok(()),
            Err(why) => return Err(ServerError::Storage(why)),
        }
    }
    pub fn handle_scan(&mut self,
                       msg: &Request,
                       msg_id: u64,
                       token: Token,
                       event_loop: &mut EventLoop<Server>)
                       -> Result<()> {
        if !msg.has_cmd_scan_req() {
            error!("Msg doesn't containe a CmdScanRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdScanRequest"
                                                    .to_string()));
        }
        let cmd_scan_req: &CmdScanRequest = msg.get_cmd_scan_req();
        let sender = event_loop.channel();
        // convert [u8] to Vec[u8]
        let start_key: Key = cmd_scan_req.get_key().iter().cloned().collect();
        debug!("start_key [{:?}]", start_key);
        match self.store
                  .async_scan(start_key,
                              cmd_scan_req.get_limit() as usize,
                              cmd_scan_req.get_version(),
                              Box::new(move |kvs: ::std::result::Result<Vec<KvPair>,
                                                                          storage::Error>| {
                                  let resp: Response = Server::cmd_scan_done(kvs);
                                  let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                  sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                              })) {
            Ok(()) => Ok(()),
            Err(why) => return Err(ServerError::Storage(why)),
        }
    }
    pub fn handle_prewrite(&mut self,
                           msg: &Request,
                           msg_id: u64,
                           token: Token,
                           event_loop: &mut EventLoop<Server>)
                           -> Result<()> {
        if !msg.has_cmd_prewrite_req() {
            error!("Msg doesn't containe a CmdPrewriteRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdPrewriteRequest"
                                                    .to_string()));
        }
        let cmd_prewrite_req: &CmdPrewriteRequest = msg.get_cmd_prewrite_req();
        let sender = event_loop.channel();
        let puts: Vec<_> = cmd_prewrite_req.get_puts()
                                           .iter()
                                           .map(|kv| {
                                               (util::array_to_vec(kv.get_key()),
                                                util::array_to_vec(kv.get_value()))
                                           })
                                           .collect();
        let deletes: Vec<_> = cmd_prewrite_req.get_dels().iter().cloned().collect();
        let locks: Vec<_> = cmd_prewrite_req.get_locks().iter().cloned().collect();
        match self.store
                  .async_prewrite(puts,
                                  deletes,
                                  locks,
                                  cmd_prewrite_req.get_start_version(),
                                  Box::new(move |r: ::std::result::Result<(),
                                                                            storage::Error>| {
                                      let resp: Response = Server::cmd_prewrite_done(r);
                                      let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                      sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                                  })) {
            Ok(()) => Ok(()),
            Err(why) => return Err(ServerError::Storage(why)),
        }
    }
    pub fn handle_commit(&mut self,
                         msg: &Request,
                         msg_id: u64,
                         token: Token,
                         event_loop: &mut EventLoop<Server>)
                         -> Result<()> {
        if !msg.has_cmd_commit_req() {
            error!("Msg doesn't containe a CmdCommitRequest");
            return Err(ServerError::FormatError("Msg doesn't containe a CmdCommitRequest"
                                                    .to_string()));
        }
        let cmd_commit_req: &CmdCommitRequest = msg.get_cmd_commit_req();
        let sender = event_loop.channel();
        match self.store
                  .async_commit(cmd_commit_req.get_start_version(),
                                cmd_commit_req.get_commit_version(),
                                Box::new(move |r: ::std::result::Result<(), storage::Error>| {
                                    let resp: Response = Server::cmd_commit_done(r);
                                    let queue_msg: QueueMessage = QueueMessage::Response(token,
                                                                                msg_id,
                                                                                resp);
                                    // [TODO]: retry
                                    sender.send(queue_msg).map_err(|e| error!("{:?}", e));
                                })) {
            Ok(()) => Ok(()),
            Err(why) => Err(ServerError::Storage(why)),
        }
    }
    fn cmd_get_done(r: ::std::result::Result<Option<Value>, storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_get_resp: CmdGetResponse = CmdGetResponse::new();
        cmd_get_resp.set_ok(r.is_ok());
        match r {
            Ok(v) => {
                match v {
                    Some(val) => cmd_get_resp.set_value(val),
                    None => cmd_get_resp.set_value(Vec::new()),
                }
                cmd_get_resp.set_ok(true);
            }
            Err(_) => {}
        }
        resp.set_field_type(MessageType::CmdGet);
        resp.set_cmd_get_resp(cmd_get_resp);
        resp
    }
    fn cmd_scan_done(kvs: ::std::result::Result<Vec<KvPair>, storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_scan_resp: CmdScanResponse = CmdScanResponse::new();
        cmd_scan_resp.set_ok(kvs.is_ok());
        match kvs {
            Ok(v) => {
                // convert storage::KvPair to kvrpcpb::KvPair
                let mut new_kvs: Vec<kvrpcpb::KvPair> = Vec::new();
                for x in &v {
                    let mut new_kv: kvrpcpb::KvPair = kvrpcpb::KvPair::new();
                    new_kv.set_key(x.0.clone());
                    new_kv.set_value(x.1.clone());
                    new_kvs.push(new_kv);
                }
                cmd_scan_resp.set_results(RepeatedField::from_vec(new_kvs));
            }
            Err(_) => {}
        }
        resp.set_field_type(MessageType::CmdScan);
        resp.set_cmd_scan_resp(cmd_scan_resp);
        resp
    }
    fn cmd_prewrite_done(r: ::std::result::Result<(), storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_prewrite_resp: CmdPrewriteResponse = CmdPrewriteResponse::new();
        cmd_prewrite_resp.set_ok(r.is_ok());
        resp.set_field_type(MessageType::CmdPrewrite);
        resp.set_cmd_prewrite_resp(cmd_prewrite_resp);
        resp
    }
    fn cmd_commit_done(r: ::std::result::Result<(), storage::Error>) -> Response {
        let mut resp: Response = Response::new();
        let mut cmd_commit_resp: CmdCommitResponse = CmdCommitResponse::new();
        cmd_commit_resp.set_ok(r.is_ok());
        resp.set_field_type(MessageType::CmdCommit);
        resp.set_cmd_commit_resp(cmd_commit_resp);
        resp
    }
}

pub enum QueueMessage {
    // Request(token, msg_id, kvrpc_request)
    Request(Token, u64, Request),
    // Request(token, msg_id, kvrpc_response)
    Response(Token, u64, Response),
    Quit,
}

impl mio::Handler for Server {
    type Timeout = ();
    type Message = QueueMessage;

    fn ready(&mut self, event_loop: &mut EventLoop<Server>, token: Token, events: EventSet) {
        if events.is_hup() || events.is_error() {
            self.conns.remove(&token);
            return;
        }

        if events.is_readable() {
            match token {
                SERVER_TOKEN => {
                    let sock = match self.listener.accept() {
                        // Some(sock, addr)
                        Ok(Some((sock, _))) => sock,
                        Ok(None) => unreachable!(),
                        Err(e) => {
                            error!("accept error: {}", e);
                            return;
                        }
                    };

                    let new_token = Token(self.token_counter);
                    match sock.set_nodelay(true) {
                        Ok(_) => {}
                        Err(e) => error!("set nodeplay failed {:?}", e),
                    }
                    self.conns.insert(new_token, Conn::new(sock));
                    self.token_counter += 1;

                    event_loop.register(&self.conns[&new_token].sock,
                                        new_token,
                                        EventSet::readable(),
                                        PollOpt::level() | PollOpt::oneshot())
                              .unwrap();

                }
                token => {
                    let mut conn: &mut Conn = match self.conns.get_mut(&token) {
                        Some(c) => c,
                        None => {
                            error!("Get connection failed token[{}]", token.0);
                            return;
                        }
                    };
                    conn.read(token, event_loop);
                    event_loop.reregister(&conn.sock,
                                          token,
                                          conn.interest,
                                          PollOpt::level() | PollOpt::oneshot())
                              .unwrap();
                }
            }
        }

        if events.is_writable() {
            let mut conn: &mut Conn = match self.conns.get_mut(&token) {
                Some(c) => c,
                None => {
                    error!("Get connection failed token[{}]", token.0);
                    return;
                }
            };
            conn.write();
            event_loop.reregister(&conn.sock,
                                  token,
                                  conn.interest,
                                  PollOpt::level() | PollOpt::oneshot())
                      .unwrap();
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Server>, msg: QueueMessage) {
        match msg {
            QueueMessage::Request(token, msg_id, req) => {
                debug!("notify Request token[{}] msg_id[{}] type[{:?}]",
                       token.0,
                       msg_id,
                       req.get_field_type());
                match req.get_field_type() {
                    MessageType::CmdGet => {
                        if let Err(e) = self.handle_get(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        };
                    }
                    MessageType::CmdScan => {
                        if let Err(e) = self.handle_scan(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        }
                    }
                    MessageType::CmdPrewrite => {
                        if let Err(e) = self.handle_prewrite(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        }
                    }
                    MessageType::CmdCommit => {
                        if let Err(e) = self.handle_commit(&req, msg_id, token, event_loop) {
                            error!("Some error occur err[{:?}]", e);
                        }
                    }
                }
            }
            QueueMessage::Response(token, msg_id, resp) => {
                debug!("notify Response token[{}] msg_id[{}] type[{:?}]",
                       token.0,
                       msg_id,
                       resp.get_field_type());
                let mut conn: &mut Conn = match self.conns.get_mut(&token) {
                    Some(c) => c,
                    None => {
                        error!("Get connection failed token[{}]", token.0);
                        return;
                    }
                };
                conn.res.clear();
                let resp_len: usize = MSG_HEADER_LEN + resp.compute_size() as usize;
                if conn.res.capacity() < resp_len {
                    conn.res = Vec::with_capacity(resp_len);
                }
                encode_msg(&mut conn.res, msg_id, &resp).unwrap();
                conn.interest.insert(EventSet::writable());
                event_loop.reregister(&conn.sock,
                                      token,
                                      conn.interest,
                                      PollOpt::level() | PollOpt::oneshot())
                          .unwrap();
            }
            QueueMessage::Quit => event_loop.shutdown(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! register_diagnostic {
    ($code:tt, $description:tt) => (__register_diagnostic! { $code, $description });
    ($code:tt) => (__register_diagnostic! { $code })
}

#[macro_export]
macro_rules! span_fatal {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        __diagnostic_used!($code);
        $session.span_fatal_with_code($span, &format!($($message)*), stringify!($code))
    })
}

#[macro_export]
macro_rules! span_err {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        __diagnostic_used!($code);
        $session.span_err_with_code($span, &format!($($message)*), stringify!($code))
    })
}

#[macro_export]
macro_rules! span_warn {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        __diagnostic_used!($code);
        $session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
    })
}

#[macro_export]
macro_rules! span_note {
    ($session:expr, $span:expr, $($message:tt)*) => ({
        ($session).span_note($span, &format!($($message)*))
    })
}

#[macro_export]
macro_rules! span_help {
    ($session:expr, $span:expr, $($message:tt)*) => ({
        ($session).span_help($span, &format!($($message)*))
    })
}

#[macro_export]
macro_rules! fileline_help {
    ($session:expr, $span:expr, $($message:tt)*) => ({
        ($session).fileline_help($span, &format!($($message)*))
    })
}

#[macro_export]
macro_rules! register_diagnostics {
    ($($code:tt),*) => (
        $(register_diagnostic! { $code })*
    );
    ($($code:tt),*,) => (
        $(register_diagnostic! { $code })*
    )
}

#[macro_export]
macro_rules! register_long_diagnostics {
    ($($code:tt: $description:tt),*) => (
        $(register_diagnostic! { $code, $description })*
    )
}
<commit_msg>Improve register_long_diagnostics macro<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! register_diagnostic {
    ($code:tt, $description:tt) => (__register_diagnostic! { $code, $description });
    ($code:tt) => (__register_diagnostic! { $code })
}

#[macro_export]
macro_rules! span_fatal {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        __diagnostic_used!($code);
        $session.span_fatal_with_code($span, &format!($($message)*), stringify!($code))
    })
}

#[macro_export]
macro_rules! span_err {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        __diagnostic_used!($code);
        $session.span_err_with_code($span, &format!($($message)*), stringify!($code))
    })
}

#[macro_export]
macro_rules! span_warn {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        __diagnostic_used!($code);
        $session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
    })
}

#[macro_export]
macro_rules! span_note {
    ($session:expr, $span:expr, $($message:tt)*) => ({
        ($session).span_note($span, &format!($($message)*))
    })
}

#[macro_export]
macro_rules! span_help {
    ($session:expr, $span:expr, $($message:tt)*) => ({
        ($session).span_help($span, &format!($($message)*))
    })
}

#[macro_export]
macro_rules! fileline_help {
    ($session:expr, $span:expr, $($message:tt)*) => ({
        ($session).fileline_help($span, &format!($($message)*))
    })
}

#[macro_export]
macro_rules! register_diagnostics {
    ($($code:tt),*) => (
        $(register_diagnostic! { $code })*
    );
    ($($code:tt),*,) => (
        $(register_diagnostic! { $code })*
    )
}

#[macro_export]
macro_rules! register_long_diagnostics {
    ($($code:tt: $description:tt),*) => (
        $(register_diagnostic! { $code, $description })*
    );
    ($($code:tt: $description:tt),*,) => (
        $(register_diagnostic! { $code, $description })*
    )
}
<|endoftext|>