<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

/// See the documentation at https://github.com/pagekite/libpagekite/blob/master/doc/API.md

use ffi::*;
use std::ffi::{CStr, CString};
use std::mem::transmute;
use std::{convert, ptr};
use std::time::Duration;
#[derive(Clone, Copy)]
pub enum InitFlags {
    WithDefaults = 0x8000,
    WithoutDefaults = 0x4000,
    WithSsl = 0x0001,
    WithIpv4 = 0x0002,
    WithIpv6 = 0x0004,
    WithServiceFrontends = 0x0008,
    WithoutServiceFrontends = 0x0010,
    WithDynamicFeList = 0x0020,
    WithFrontendSni = 0x0040,
    AsFrontendRelay = 0x0100,
    WithSyslog = 0x0200,
}

#[derive(Clone, Copy)]
pub enum VerbosityFlags {
    LogTunnelData = 0x000100,
    LogTunnelHeaders = 0x000200,
    LogTunnelConns = 0x000400,
    LogBeData = 0x001000,
    LogBeHeaders = 0x002000,
    LogBeConns = 0x004000,
    LogManagerError = 0x010000,
    LogManagerInfo = 0x020000,
    LogManagerDebug = 0x040000,
    LogTrace = 0x080000,
    LogLuaDebug = 0x008000,
    LogLuaInfo = 0x000800,
    LogError = 0x100000,
}

#[repr(i32)]
pub enum Status {
    Startup = 10,
    Connecting = 20,
    UpdatingDns = 30,
    Flying = 40,
    PROProblems = 50,
    Rejected = 60,
    NoNetwork = 90,
}

impl convert::Into<Status> for i32 {
    fn into(self) -> Status {
        unsafe { transmute::<i32, Status>(self) }
    }
}

pub static LOG_ERRORS: [VerbosityFlags; 2] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError];
pub static LOG_MANAGER: [VerbosityFlags; 2] = [VerbosityFlags::LogManagerError,
                                               VerbosityFlags::LogManagerInfo];
pub static LOG_CONNS: [VerbosityFlags; 2] = [VerbosityFlags::LogBeConns,
                                             VerbosityFlags::LogTunnelConns];
pub static LOG_NORMAL: [VerbosityFlags; 7] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogBeConns,
                                              VerbosityFlags::LogTunnelConns,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogManagerInfo,
                                              VerbosityFlags::LogLuaInfo];
pub static LOG_ALL: [VerbosityFlags; 13] = [VerbosityFlags::LogTunnelData,
                                            VerbosityFlags::LogTunnelHeaders,
                                            VerbosityFlags::LogTunnelConns,
                                            VerbosityFlags::LogBeData,
                                            VerbosityFlags::LogBeHeaders,
                                            VerbosityFlags::LogBeConns,
                                            VerbosityFlags::LogManagerError,
                                            VerbosityFlags::LogManagerInfo,
                                            VerbosityFlags::LogManagerDebug,
                                            VerbosityFlags::LogTrace,
                                            VerbosityFlags::LogLuaDebug,
                                            VerbosityFlags::LogLuaInfo,
                                            VerbosityFlags::LogError];

#[derive(Clone)]
pub struct PageKite {
    inner: pagekite_mgr,
}

unsafe impl Send for PageKite {}

macro_rules! str_cstring(
    ($a:ident) => ( CString::new($a).unwrap().as_ptr() )
);

macro_rules! build_flag(
    ($flag:ident, $array:ident) => (
        let mut $flag = 0;
        for item in $array {
            $flag |= *item as i32;
        }
    )
);

#[inline]
fn bool2int(val: bool) -> i32 {
    if val { 1 } else { 0 }
}

impl PageKite {
    pub fn init(app_id: Option<&str>,
                max_kites: i32,
                max_frontends: i32,
                max_conns: i32,
                dyndns_url: Option<&str>,
                flags: &[InitFlags],
                verbosity: &[VerbosityFlags])
                -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_dyndns_url = match dyndns_url {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init(c_app_id,
                          max_kites,
                          max_frontends,
                          max_conns,
                          c_dyndns_url,
                          c_flags,
                          c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_pagekitenet(app_id: Option<&str>,
                            max_kites: i32,
                            max_conns: i32,
                            flags: &[InitFlags],
                            verbosity: &[VerbosityFlags])
                            -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_pagekitenet(c_app_id, max_kites, max_conns, c_flags, c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_whitelabel(app_id: Option<&str>,
                           max_kites: i32,
                           max_conns: i32,
                           flags: &[InitFlags],
                           verbosity: &[VerbosityFlags],
                           whitelabel_tld: Option<&str>)
                           -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_whitelabel(c_app_id, max_kites, max_conns, c_flags, c_verbosity, c_tld)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn add_kite(&self,
                    proto: &str,
                    kitename: &str,
                    public_port: i32,
                    secret: &str,
                    backend: &str,
                    local_port: i32)
                    -> bool {

        return unsafe {
                   pagekite_add_kite(self.inner,
                                     str_cstring!(proto),
                                     str_cstring!(kitename),
                                     public_port,
                                     str_cstring!(secret),
                                     str_cstring!(backend),
                                     local_port)
               } == 0;
    }

    /// Useful flags are WithDefaults, WithIpv4, WithIpv6, WithDynamicFeList
    /// Returns the number of frontend ips, or an empty error.
    pub fn add_service_frontends(&self, flags: &[InitFlags]) -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let ret = unsafe { pagekite_add_service_frontends(self.inner, c_flags) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn add_whitelabel_frontends(&self,
                                    flags: &[InitFlags],
                                    whitelabel_tld: Option<&str>)
                                    -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };
        let ret = unsafe { pagekite_add_whitelabel_frontends(self.inner, c_flags, c_tld) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn lookup_and_add_frontend(&self,
                                   domain: &str,
                                   port: i32,
                                   update_from_dns: bool)
                                   -> Option<i32> {
        let count = unsafe {
            pagekite_lookup_and_add_frontend(self.inner,
                                             str_cstring!(domain),
                                             port,
                                             if update_from_dns { 1 } else { 0 })
        };
        if count == -1 { None } else { Some(count) }
    }

    pub fn add_frontend(&self, domain: &str, port: i32) -> Option<i32> {
        let count = unsafe { pagekite_add_frontend(self.inner, str_cstring!(domain), port) };
        if count == -1 { None } else { Some(count) }
    }

    pub fn set_log_mask(&self, flags: &[VerbosityFlags]) {
        build_flag!(c_verbosity, flags);
        unsafe {
            pagekite_set_log_mask(self.inner, c_verbosity);
        }
    }

    pub fn set_housekeeping_min_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_min_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn set_housekeeping_max_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_max_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn enable_http_forwarding_headers(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_http_forwarding_headers(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_fake_ping(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_fake_ping(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_watchdog(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_watchdog(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_tick_timer(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_tick_timer(self.inner, bool2int(enable));
        }
        self
    }

    pub fn set_conn_eviction_idle_s(&self, seconds: Duration) -> &Self {
        unsafe {
            pagekite_set_conn_eviction_idle_s(self.inner, seconds.as_secs() as i32);
        }
        self
    }

    pub fn set_openssl_ciphers(&self, ciphers: &str) -> &Self {
        unsafe {
            pagekite_set_openssl_ciphers(self.inner, str_cstring!(ciphers));
        }
        self
    }

    pub fn want_spare_frontends(&self, spares: i32) -> &Self {
        unsafe {
            pagekite_want_spare_frontends(self.inner, spares);
        }
        self
    }

    pub fn thread_start(&self) -> bool {
        return unsafe { pagekite_thread_start(self.inner) } == 0;
    }

    pub fn thread_wait(&self) -> bool {
        return unsafe { pagekite_thread_wait(self.inner) } == 0;
    }

    pub fn thread_stop(&self) -> bool {
        return unsafe { pagekite_thread_stop(self.inner) } == 0;
    }

    pub fn get_status(&self) -> Status {
        return unsafe { pagekite_get_status(self.inner) }.into();
    }

    pub fn get_log(&self) -> String {
        unsafe {
            CStr::from_ptr(pagekite_get_log(self.inner))
                .to_string_lossy()
                .into_owned()
        }
    }

    pub fn dump_state_to_log(&self) -> &Self {
        unsafe {
            pagekite_dump_state_to_log(self.inner);
        }
        self
    }

    pub fn poll(&self, timeout: Duration) -> bool {
        return unsafe { pagekite_poll(self.inner, timeout.as_secs() as i32) } == 0;
    }

    pub fn tick(&self) -> bool {
        return unsafe { pagekite_tick(self.inner) } == 0;
    }
}

impl Drop for PageKite {
    fn drop(&mut self) {
        unsafe {
            pagekite_thread_stop(self.inner);
            pagekite_free(self.inner);
        }
    }
}
<commit_msg>Implement Sync on PageKite<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

/// See the documentation at https://github.com/pagekite/libpagekite/blob/master/doc/API.md

use ffi::*;
use std::ffi::{CStr, CString};
use std::mem::transmute;
use std::{convert, ptr};
use std::time::Duration;
#[derive(Clone, Copy)]
pub enum InitFlags {
    WithDefaults = 0x8000,
    WithoutDefaults = 0x4000,
    WithSsl = 0x0001,
    WithIpv4 = 0x0002,
    WithIpv6 = 0x0004,
    WithServiceFrontends = 0x0008,
    WithoutServiceFrontends = 0x0010,
    WithDynamicFeList = 0x0020,
    WithFrontendSni = 0x0040,
    AsFrontendRelay = 0x0100,
    WithSyslog = 0x0200,
}

#[derive(Clone, Copy)]
pub enum VerbosityFlags {
    LogTunnelData = 0x000100,
    LogTunnelHeaders = 0x000200,
    LogTunnelConns = 0x000400,
    LogBeData = 0x001000,
    LogBeHeaders = 0x002000,
    LogBeConns = 0x004000,
    LogManagerError = 0x010000,
    LogManagerInfo = 0x020000,
    LogManagerDebug = 0x040000,
    LogTrace = 0x080000,
    LogLuaDebug = 0x008000,
    LogLuaInfo = 0x000800,
    LogError = 0x100000,
}

#[repr(i32)]
pub enum Status {
    Startup = 10,
    Connecting = 20,
    UpdatingDns = 30,
    Flying = 40,
    PROProblems = 50,
    Rejected = 60,
    NoNetwork = 90,
}

impl convert::Into<Status> for i32 {
    fn into(self) -> Status {
        unsafe { transmute::<i32, Status>(self) }
    }
}

pub static LOG_ERRORS: [VerbosityFlags; 2] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError];
pub static LOG_MANAGER: [VerbosityFlags; 2] = [VerbosityFlags::LogManagerError,
                                               VerbosityFlags::LogManagerInfo];
pub static LOG_CONNS: [VerbosityFlags; 2] = [VerbosityFlags::LogBeConns,
                                             VerbosityFlags::LogTunnelConns];
pub static LOG_NORMAL: [VerbosityFlags; 7] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogBeConns,
                                              VerbosityFlags::LogTunnelConns,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogManagerInfo,
                                              VerbosityFlags::LogLuaInfo];
pub static LOG_ALL: [VerbosityFlags; 13] = [VerbosityFlags::LogTunnelData,
                                            VerbosityFlags::LogTunnelHeaders,
                                            VerbosityFlags::LogTunnelConns,
                                            VerbosityFlags::LogBeData,
                                            VerbosityFlags::LogBeHeaders,
                                            VerbosityFlags::LogBeConns,
                                            VerbosityFlags::LogManagerError,
                                            VerbosityFlags::LogManagerInfo,
                                            VerbosityFlags::LogManagerDebug,
                                            VerbosityFlags::LogTrace,
                                            VerbosityFlags::LogLuaDebug,
                                            VerbosityFlags::LogLuaInfo,
                                            VerbosityFlags::LogError];

#[derive(Clone)]
pub struct PageKite {
    inner: pagekite_mgr,
}

unsafe impl Send for PageKite {}
unsafe impl Sync for PageKite {}

macro_rules! str_cstring(
    ($a:ident) => ( CString::new($a).unwrap().as_ptr() )
);

macro_rules! build_flag(
    ($flag:ident, $array:ident) => (
        let mut $flag = 0;
        for item in $array {
            $flag |= *item as i32;
        }
    )
);

#[inline]
fn bool2int(val: bool) -> i32 {
    if val { 1 } else { 0 }
}

impl PageKite {
    pub fn init(app_id: Option<&str>,
                max_kites: i32,
                max_frontends: i32,
                max_conns: i32,
                dyndns_url: Option<&str>,
                flags: &[InitFlags],
                verbosity: &[VerbosityFlags])
                -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_dyndns_url = match dyndns_url {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init(c_app_id,
                          max_kites,
                          max_frontends,
                          max_conns,
                          c_dyndns_url,
                          c_flags,
                          c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_pagekitenet(app_id: Option<&str>,
                            max_kites: i32,
                            max_conns: i32,
                            flags: &[InitFlags],
                            verbosity: &[VerbosityFlags])
                            -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_pagekitenet(c_app_id, max_kites, max_conns, c_flags, c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_whitelabel(app_id: Option<&str>,
                           max_kites: i32,
                           max_conns: i32,
                           flags: &[InitFlags],
                           verbosity: &[VerbosityFlags],
                           whitelabel_tld: Option<&str>)
                           -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_whitelabel(c_app_id, max_kites, max_conns, c_flags, c_verbosity, c_tld)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn add_kite(&self,
                    proto: &str,
                    kitename: &str,
                    public_port: i32,
                    secret: &str,
                    backend: &str,
                    local_port: i32)
                    -> bool {

        return unsafe {
                   pagekite_add_kite(self.inner,
                                     str_cstring!(proto),
                                     str_cstring!(kitename),
                                     public_port,
                                     str_cstring!(secret),
                                     str_cstring!(backend),
                                     local_port)
               } == 0;
    }

    /// Useful flags are WithDefaults, WithIpv4, WithIpv6, WithDynamicFeList
    /// Returns the number of frontend ips, or an empty error.
    pub fn add_service_frontends(&self, flags: &[InitFlags]) -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let ret = unsafe { pagekite_add_service_frontends(self.inner, c_flags) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn add_whitelabel_frontends(&self,
                                    flags: &[InitFlags],
                                    whitelabel_tld: Option<&str>)
                                    -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };
        let ret = unsafe { pagekite_add_whitelabel_frontends(self.inner, c_flags, c_tld) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn lookup_and_add_frontend(&self,
                                   domain: &str,
                                   port: i32,
                                   update_from_dns: bool)
                                   -> Option<i32> {
        let count = unsafe {
            pagekite_lookup_and_add_frontend(self.inner,
                                             str_cstring!(domain),
                                             port,
                                             if update_from_dns { 1 } else { 0 })
        };
        if count == -1 { None } else { Some(count) }
    }

    pub fn add_frontend(&self, domain: &str, port: i32) -> Option<i32> {
        let count = unsafe { pagekite_add_frontend(self.inner, str_cstring!(domain), port) };
        if count == -1 { None } else { Some(count) }
    }

    pub fn set_log_mask(&self, flags: &[VerbosityFlags]) {
        build_flag!(c_verbosity, flags);
        unsafe {
            pagekite_set_log_mask(self.inner, c_verbosity);
        }
    }

    pub fn set_housekeeping_min_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_min_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn set_housekeeping_max_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_max_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn enable_http_forwarding_headers(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_http_forwarding_headers(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_fake_ping(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_fake_ping(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_watchdog(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_watchdog(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_tick_timer(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_tick_timer(self.inner, bool2int(enable));
        }
        self
    }

    pub fn set_conn_eviction_idle_s(&self, seconds: Duration) -> &Self {
        unsafe {
            pagekite_set_conn_eviction_idle_s(self.inner, seconds.as_secs() as i32);
        }
        self
    }

    pub fn set_openssl_ciphers(&self, ciphers: &str) -> &Self {
        unsafe {
            pagekite_set_openssl_ciphers(self.inner, str_cstring!(ciphers));
        }
        self
    }

    pub fn want_spare_frontends(&self, spares: i32) -> &Self {
        unsafe {
            pagekite_want_spare_frontends(self.inner, spares);
        }
        self
    }

    pub fn thread_start(&self) -> bool {
        return unsafe { pagekite_thread_start(self.inner) } == 0;
    }

    pub fn thread_wait(&self) -> bool {
        return unsafe { pagekite_thread_wait(self.inner) } == 0;
    }

    pub fn thread_stop(&self) -> bool {
        return unsafe { pagekite_thread_stop(self.inner) } == 0;
    }

    pub fn get_status(&self) -> Status {
        return unsafe { pagekite_get_status(self.inner) }.into();
    }

    pub fn get_log(&self) -> String {
        unsafe {
            CStr::from_ptr(pagekite_get_log(self.inner))
                .to_string_lossy()
                .into_owned()
        }
    }

    pub fn dump_state_to_log(&self) -> &Self {
        unsafe {
            pagekite_dump_state_to_log(self.inner);
        }
        self
    }

    pub fn poll(&self, timeout: Duration) -> bool {
        return unsafe { pagekite_poll(self.inner, timeout.as_secs() as i32) } == 0;
    }

    pub fn tick(&self) -> bool {
        return unsafe { pagekite_tick(self.inner) } == 0;
    }
}

impl Drop for PageKite {
    fn drop(&mut self) {
        unsafe {
            pagekite_thread_stop(self.inner);
            pagekite_free(self.inner);
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{IoError, MemReader};
use std::fmt;
use std::fmt::{Show, Formatter, FormatError};
use std::collections::HashMap;

use conduit::Response;
use curl::ErrCode;
use pg::error::{PostgresError, PostgresConnectError};
use serialize::json;
use git2;

use util::json_response;

pub trait CargoError: Send {
    fn description(&self) -> String;
    fn detail(&self) -> Option<String> { None }
    fn cause<'a>(&'a self) -> Option<&'a CargoError + Send> { None }

    fn to_error<E: FromError<Self>>(self) -> E {
        FromError::from_error(self)
    }

    fn box_error(self) -> Box<CargoError + Send> {
        box self as Box<CargoError + Send>
    }

    fn concrete(&self) -> ConcreteCargoError {
        ConcreteCargoError {
            description: self.description(),
            detail: self.detail(),
            cause: self.cause().map(|c| box c.concrete() as Box<CargoError + Send>),
            human: false,
        }
    }

    fn with_cause<E: CargoError + Send>(self, cause: E) -> Box<CargoError + Send> {
        let mut concrete = self.concrete();
        concrete.cause = Some(cause.box_error());
        box concrete as Box<CargoError + Send>
    }

    fn response(&self) -> Option<Response> {
        #[deriving(Encodable)] struct Bad { ok: bool, error: String }

        if self.human() {
            Some(json_response(&Bad {
                ok: false,
                error: self.description(),
            }))
        } else {
            self.cause().and_then(|cause| cause.response())
        }
    }
    fn human(&self) -> bool { false }
}

pub trait FromError<E> {
    fn from_error(error: E) -> Self;
}

impl<E: CargoError + Send> FromError<E> for Box<CargoError + Send> {
    fn from_error(error: E) -> Box<CargoError + Send> {
        error.box_error()
    }
}

macro_rules! from_error (
    ($ty:ty) => {
        impl FromError<$ty> for $ty {
            fn from_error(error: $ty) -> $ty {
                error
            }
        }
    }
)

impl<'a> Show for &'a CargoError + Send {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description()));

        match self.detail() {
            Some(s) => try!(write!(f, "\n  {}", s)),
            None => {}
        }

        match self.cause() {
            Some(cause) => try!(write!(f, "\nCaused by: {}", cause)),
            None => {}
        }

        Ok(())
    }
}

impl Show for Box<CargoError + Send> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let me: &CargoError + Send = &**self;
        me.fmt(f)
    }
}

impl CargoError for Box<CargoError + Send> {
    fn description(&self) -> String { (*self).description() }
    fn detail(&self) -> Option<String> { (*self).detail() }
    fn cause<'a>(&'a self) -> Option<&'a CargoError + Send> { (*self).cause() }
    fn box_error(self) -> Box<CargoError + Send> { self }
    fn human(&self) -> bool { (*self).human() }
    fn response(&self) -> Option<Response> { (*self).response() }
}

pub type CargoResult<T> = Result<T, Box<CargoError + Send>>;

pub trait BoxError<T> {
    fn box_error(self) -> CargoResult<T>;
}

pub trait ChainError<T> {
    fn chain_error<E: CargoError + Send>(self, callback: || -> E) -> CargoResult<T> ;
}

impl<'a, T> ChainError<T> for ||:'a -> CargoResult<T> {
    fn chain_error<E: CargoError + Send>(self, callback: || -> E) -> CargoResult<T> {
        self().map_err(|err| callback().with_cause(err))
    }
}

impl<T, E: CargoError + Send> BoxError<T> for Result<T, E> {
    fn box_error(self) -> CargoResult<T> {
        self.map_err(|err| err.box_error())
    }
}

impl<T, E: CargoError + Send> ChainError<T> for Result<T, E> {
    fn chain_error<E: CargoError + Send>(self, callback: || -> E) -> CargoResult<T>  {
        self.map_err(|err| callback().with_cause(err))
    }
}

impl CargoError for IoError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(IoError)

impl CargoError for FormatError {
    fn description(&self) -> String {
        "formatting failed".to_string()
    }
}

from_error!(FormatError)

impl CargoError for PostgresError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(PostgresError)

impl CargoError for PostgresConnectError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(PostgresConnectError)

impl CargoError for ErrCode {
    fn description(&self) -> String { self.to_string() }
}

from_error!(ErrCode)

impl CargoError for json::DecoderError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(json::DecoderError)

impl CargoError for git2::Error {
    fn description(&self) -> String { self.to_string() }
}

from_error!(git2::Error)

impl<T: CargoError + Send> FromError<T> for Box<Show + 'static> {
    fn from_error(t: T) -> Box<Show + 'static> {
        box() (box t as Box<CargoError + Send>) as Box<Show + 'static>
    }
}

pub struct ConcreteCargoError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<CargoError + Send>>,
    human: bool,
}

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

impl CargoError for ConcreteCargoError {
    fn description(&self) -> String {
        self.description.clone()
    }

    fn detail(&self) -> Option<String> {
        self.detail.clone()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError + Send> {
        self.cause.as_ref().map(|c| { let err: &CargoError + Send = &**c; err })
    }

    fn with_cause<E: CargoError + Send>(mut self,
                                        err: E) -> Box<CargoError + Send> {
        self.cause = Some(err.box_error());
        box self as Box<CargoError + Send>
    }
    fn human(&self) -> bool { self.human }
}

pub struct NotFound;

impl CargoError for NotFound {
    fn description(&self) -> String { "not found".to_string() }

    fn response(&self) -> Option<Response> {
        Some(Response {
            status: (404, "Not Found"),
            headers: HashMap::new(),
            body: box MemReader::new(Vec::new()),
        })
    }
}

from_error!(NotFound)

pub struct Unauthorized;

impl CargoError for Unauthorized {
    fn description(&self) -> String { "unauthorized".to_string() }

    fn response(&self) -> Option<Response> {
        Some(Response {
            status: (403, "Forbidden"),
            headers: HashMap::new(),
            body: box MemReader::new(Vec::new()),
        })
    }
}

from_error!(Unauthorized)

pub fn internal_error<S1: Str, S2: Str>(error: S1,
                                        detail: S2) -> Box<CargoError + Send> {
    box ConcreteCargoError {
        description: error.as_slice().to_string(),
        detail: Some(detail.as_slice().to_string()),
        cause: None,
        human: false,
    } as Box<CargoError + Send>
}

pub fn internal<S: Show>(error: S) -> Box<CargoError + Send> {
    box ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        human: false,
    } as Box<CargoError + Send>
}

pub fn human<S: Show>(error: S) -> Box<CargoError + Send> {
    box ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        human: true,
    } as Box<CargoError + Send>
}
<commit_msg>Fix infinite recursion<commit_after>use std::io::{IoError, MemReader};
use std::fmt;
use std::fmt::{Show, Formatter, FormatError};
use std::collections::HashMap;

use conduit::Response;
use curl::ErrCode;
use pg::error::{PostgresError, PostgresConnectError};
use serialize::json;
use git2;

use util::json_response;

pub trait CargoError: Send {
    fn description(&self) -> String;
    fn detail(&self) -> Option<String> { None }
    fn cause<'a>(&'a self) -> Option<&'a CargoError + Send> { None }

    fn to_error<E: FromError<Self>>(self) -> E {
        FromError::from_error(self)
    }

    fn box_error(self) -> Box<CargoError + Send> {
        box self as Box<CargoError + Send>
    }

    fn concrete(&self) -> ConcreteCargoError {
        ConcreteCargoError {
            description: self.description(),
            detail: self.detail(),
            cause: self.cause().map(|c| box c.concrete() as Box<CargoError + Send>),
            human: false,
        }
    }

    fn with_cause<E: CargoError + Send>(self, cause: E) -> Box<CargoError + Send> {
        let mut concrete = self.concrete();
        concrete.cause = Some(cause.box_error());
        box concrete as Box<CargoError + Send>
    }

    fn response(&self) -> Option<Response> {
        #[deriving(Encodable)] struct Bad { ok: bool, error: String }

        if self.human() {
            Some(json_response(&Bad {
                ok: false,
                error: self.description(),
            }))
        } else {
            self.cause().and_then(|cause| cause.response())
        }
    }
    fn human(&self) -> bool { false }
}

pub trait FromError<E> {
    fn from_error(error: E) -> Self;
}

impl<E: CargoError + Send> FromError<E> for Box<CargoError + Send> {
    fn from_error(error: E) -> Box<CargoError + Send> {
        error.box_error()
    }
}

macro_rules! from_error (
    ($ty:ty) => {
        impl FromError<$ty> for $ty {
            fn from_error(error: $ty) -> $ty {
                error
            }
        }
    }
)

impl<'a> Show for &'a CargoError + Send {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description()));

        match self.detail() {
            Some(s) => try!(write!(f, "\n  {}", s)),
            None => {}
        }

        match self.cause() {
            Some(cause) => try!(write!(f, "\nCaused by: {}", cause)),
            None => {}
        }

        Ok(())
    }
}

impl Show for Box<CargoError + Send> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let me: &CargoError + Send = &**self;
        me.fmt(f)
    }
}

impl CargoError for Box<CargoError + Send> {
    fn description(&self) -> String { (**self).description() }
    fn detail(&self) -> Option<String> { (**self).detail() }
    fn cause<'a>(&'a self) -> Option<&'a CargoError + Send> { (**self).cause() }
    fn box_error(self) -> Box<CargoError + Send> { self }
    fn human(&self) -> bool { (**self).human() }
    fn response(&self) -> Option<Response> { (**self).response() }
}

pub type CargoResult<T> = Result<T, Box<CargoError + Send>>;

pub trait BoxError<T> {
    fn box_error(self) -> CargoResult<T>;
}

pub trait ChainError<T> {
    fn chain_error<E: CargoError + Send>(self, callback: || -> E) -> CargoResult<T> ;
}

impl<'a, T> ChainError<T> for ||:'a -> CargoResult<T> {
    fn chain_error<E: CargoError + Send>(self, callback: || -> E) -> CargoResult<T> {
        self().map_err(|err| callback().with_cause(err))
    }
}

impl<T, E: CargoError + Send> BoxError<T> for Result<T, E> {
    fn box_error(self) -> CargoResult<T> {
        self.map_err(|err| err.box_error())
    }
}

impl<T, E: CargoError + Send> ChainError<T> for Result<T, E> {
    fn chain_error<E: CargoError + Send>(self, callback: || -> E) -> CargoResult<T>  {
        self.map_err(|err| callback().with_cause(err))
    }
}

impl CargoError for IoError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(IoError)

impl CargoError for FormatError {
    fn description(&self) -> String {
        "formatting failed".to_string()
    }
}

from_error!(FormatError)

impl CargoError for PostgresError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(PostgresError)

impl CargoError for PostgresConnectError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(PostgresConnectError)

impl CargoError for ErrCode {
    fn description(&self) -> String { self.to_string() }
}

from_error!(ErrCode)

impl CargoError for json::DecoderError {
    fn description(&self) -> String { self.to_string() }
}

from_error!(json::DecoderError)

impl CargoError for git2::Error {
    fn description(&self) -> String { self.to_string() }
}

from_error!(git2::Error)

impl<T: CargoError + Send> FromError<T> for Box<Show + 'static> {
    fn from_error(t: T) -> Box<Show + 'static> {
        box() (box t as Box<CargoError + Send>) as Box<Show + 'static>
    }
}

pub struct ConcreteCargoError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<CargoError + Send>>,
    human: bool,
}

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

impl CargoError for ConcreteCargoError {
    fn description(&self) -> String {
        self.description.clone()
    }

    fn detail(&self) -> Option<String> {
        self.detail.clone()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError + Send> {
        self.cause.as_ref().map(|c| { let err: &CargoError + Send = &**c; err })
    }

    fn with_cause<E: CargoError + Send>(mut self,
                                        err: E) -> Box<CargoError + Send> {
        self.cause = Some(err.box_error());
        box self as Box<CargoError + Send>
    }
    fn human(&self) -> bool { self.human }
}

pub struct NotFound;

impl CargoError for NotFound {
    fn description(&self) -> String { "not found".to_string() }

    fn response(&self) -> Option<Response> {
        Some(Response {
            status: (404, "Not Found"),
            headers: HashMap::new(),
            body: box MemReader::new(Vec::new()),
        })
    }
}

from_error!(NotFound)

pub struct Unauthorized;

impl CargoError for Unauthorized {
    fn description(&self) -> String { "unauthorized".to_string() }

    fn response(&self) -> Option<Response> {
        Some(Response {
            status: (403, "Forbidden"),
            headers: HashMap::new(),
            body: box MemReader::new(Vec::new()),
        })
    }
}

from_error!(Unauthorized)

pub fn internal_error<S1: Str, S2: Str>(error: S1,
                                        detail: S2) -> Box<CargoError + Send> {
    box ConcreteCargoError {
        description: error.as_slice().to_string(),
        detail: Some(detail.as_slice().to_string()),
        cause: None,
        human: false,
    } as Box<CargoError + Send>
}

pub fn internal<S: Show>(error: S) -> Box<CargoError + Send> {
    box ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        human: false,
    } as Box<CargoError + Send>
}

pub fn human<S: Show>(error: S) -> Box<CargoError + Send> {
    box ConcreteCargoError {
        description: error.to_string(),
        detail: None,
        cause: None,
        human: true,
    } as Box<CargoError + Send>
}
<|endoftext|>


<commit_before>use std::str;
use std::hashmap::HashMap;

use log::{HTTPLogRecord, LogProcessor};

// TODO: Should be moved outside
static NUMBER_OF_ITEMS: uint = 8u;

struct ObjectStats {
    client: ~str,
    requests: uint,
    request_time: uint,
    sent_bytes: uint
}

pub struct LogStats {
    priv clients: HashMap<~str, ObjectStats>
}

impl LogStats {
    pub fn new() -> ~LogStats {
        ~LogStats{clients: HashMap::new()}
    }

    pub fn print(&self) {
        let mut sorted: ~[&ObjectStats] = self.clients.values().collect();
        sorted.sort_by(|a, b| b.requests.cmp(&a.requests));
        print_sorted(sorted, "By requests");
        sorted.sort_by(|a, b| b.request_time.cmp(&a.request_time));
        print_sorted(sorted, "By request time");
        sorted.sort_by(|a, b| b.sent_bytes.cmp(&a.sent_bytes));
        print_sorted(sorted, "By sent bytes");
    }
}

impl LogProcessor for LogStats {
    fn process(&mut self, record: HTTPLogRecord) {
        if !update(self, &record) {
            let stats = ObjectStats{
                client: record.remote_addr.to_owned(),
                requests: 1,
                request_time: record.request_time,
                sent_bytes: record.sent_bytes,
                };
            self.clients.insert(record.remote_addr, stats);
        }
    }
}

fn update(stats: &mut LogStats, record: &HTTPLogRecord) -> bool {
    match stats.clients.find_mut(&record.remote_addr) {
        Some(stats) => {
            stats.requests += 1;
            stats.request_time += record.request_time;
            stats.sent_bytes += record.sent_bytes;
            true
        }
        None => false
    }
}

fn print_sorted(sorted: &[&ObjectStats], message: &str) {
    println!("\n  {}", message);
    println!("=====================================================\
              =============");
    println!("Client                                 \
              Requests   Duration   Bytes");
    println!("-----------------------------------------------------\
              -------------");
    for stats in sorted.iter().take(NUMBER_OF_ITEMS) {
        println!("{: <40} {: >6} {: >10} {: >7}",
                 stats.client, stats.requests,
                 format_duration(stats.request_time),
                 format_bytes(stats.sent_bytes));
    }
}

fn format_duration(duration: uint) -> ~str {
    let (mut n, mut pos, modifier) = if duration < 1000 {
            (duration, 3, ~"s")
        } else if duration < 60 * 1000 {
            (duration / 100, 1, ~"s")
        } else if duration < 60 * 60 * 1000 {
            (duration / 6000, 1, ~"m")
        } else {
            (duration / 360000, 1, ~"h")
        };
    while pos > 0 && n % 10 == 0 {
        n /= 10;
        pos -= 1;
    }
    let int_part = (n / pow(10, pos)).to_str();
    let mut fract_part = str::with_capacity(pos + 1);
    if pos != 0 && n != 0 {
        fract_part.push_char('.');
        while pos > 0 {
            let digit = (n / pow(10, pos - 1)) % 10;
            fract_part.push_char((digit as u8 + '0' as u8) as char);
            pos -= 1;
        }
    }
    int_part + fract_part + modifier
}

fn pow(n: uint, p: uint) -> uint {
    let mut num = 1;
    for _ in range(0, p) {
        num *= n;
    }
    num
}

fn format_bytes(mut bytes: uint) -> ~str {
    static modifiers: [&'static str, ..4] = ["G", "M", "K", ""];
    let mut i = modifiers.len() - 1;
    while bytes >= 1024 && i != 0 {
        bytes /= 1024;
        i -= 1;
    }
    bytes.to_str() + modifiers[i]
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{format_duration, format_bytes};

    #[test]
    fn test_format_duration() {
        assert_eq!(~"0s", format_duration(0));
        assert_eq!(~"0.009s", format_duration(9));
        assert_eq!(~"0.09s", format_duration(90));
        assert_eq!(~"0.9s", format_duration(900));
        assert_eq!(~"0.999s", format_duration(999));
        assert_eq!(~"1s", format_duration(1000));
        assert_eq!(~"1s", format_duration(1009));
        assert_eq!(~"1.4s", format_duration(1400));
        assert_eq!(~"1.6s", format_duration(1600));
        assert_eq!(~"59s", format_duration(59000));
        assert_eq!(~"1m", format_duration(60000));
        assert_eq!(~"1.5m", format_duration(90000));
        assert_eq!(~"1h", format_duration(60 * 60 * 1000));
        assert_eq!(~"1.5h", format_duration(90 * 60 * 1000));
        assert_eq!(~"10h", format_duration(10 * 60 * 60 * 1000));
    }

    #[test]
    fn test_format_bytes() {
        assert_eq!(~"0", format_bytes(0));
        assert_eq!(~"9", format_bytes(9));
        assert_eq!(~"90", format_bytes(90));
        assert_eq!(~"900", format_bytes(900));
        assert_eq!(~"1000", format_bytes(1000));
        assert_eq!(~"1K", format_bytes(1024));
        assert_eq!(~"2K", format_bytes(2048));
        assert_eq!(~"4K", format_bytes(4096));
        assert_eq!(~"1M", format_bytes(1024 * 1024));
        assert_eq!(~"1G", format_bytes(1024 * 1024 * 1024));
        assert_eq!(~"1024G", format_bytes(1024 * 1024 * 1024 * 1024));
    }
}
<commit_msg>Replace find_mut/insert with insert_or_update_with()<commit_after>use std::str;
use std::hashmap::HashMap;

use log::{HTTPLogRecord, LogProcessor};

// TODO: Should be moved outside
static NUMBER_OF_ITEMS: uint = 8u;

struct ObjectStats {
    client: ~str,
    requests: uint,
    request_time: uint,
    sent_bytes: uint
}

pub struct LogStats {
    priv clients: HashMap<~str, ObjectStats>
}

impl LogStats {
    pub fn new() -> ~LogStats {
        ~LogStats{clients: HashMap::new()}
    }

    pub fn print(&self) {
        let mut sorted: ~[&ObjectStats] = self.clients.values().collect();
        sorted.sort_by(|a, b| b.requests.cmp(&a.requests));
        print_sorted(sorted, "By requests");
        sorted.sort_by(|a, b| b.request_time.cmp(&a.request_time));
        print_sorted(sorted, "By request time");
        sorted.sort_by(|a, b| b.sent_bytes.cmp(&a.sent_bytes));
        print_sorted(sorted, "By sent bytes");
    }
}

impl LogProcessor for LogStats {
    fn process(&mut self, record: HTTPLogRecord) {
        self.clients.insert_or_update_with(
            record.remote_addr.to_owned(),
            ObjectStats{
                client: record.remote_addr.to_owned(),
                requests: 1,
                request_time: record.request_time,
                sent_bytes: record.sent_bytes,
                },
            |_, stats| {
                stats.requests += 1;
                stats.request_time += record.request_time;
                stats.sent_bytes += record.sent_bytes;
            });
    }
}

fn print_sorted(sorted: &[&ObjectStats], message: &str) {
    println!("\n  {}", message);
    println!("=====================================================\
              =============");
    println!("Client                                 \
              Requests   Duration   Bytes");
    println!("-----------------------------------------------------\
              -------------");
    for stats in sorted.iter().take(NUMBER_OF_ITEMS) {
        println!("{: <40} {: >6} {: >10} {: >7}",
                 stats.client, stats.requests,
                 format_duration(stats.request_time),
                 format_bytes(stats.sent_bytes));
    }
}

fn format_duration(duration: uint) -> ~str {
    let (mut n, mut pos, modifier) = if duration < 1000 {
            (duration, 3, ~"s")
        } else if duration < 60 * 1000 {
            (duration / 100, 1, ~"s")
        } else if duration < 60 * 60 * 1000 {
            (duration / 6000, 1, ~"m")
        } else {
            (duration / 360000, 1, ~"h")
        };
    while pos > 0 && n % 10 == 0 {
        n /= 10;
        pos -= 1;
    }
    let int_part = (n / pow(10, pos)).to_str();
    let mut fract_part = str::with_capacity(pos + 1);
    if pos != 0 && n != 0 {
        fract_part.push_char('.');
        while pos > 0 {
            let digit = (n / pow(10, pos - 1)) % 10;
            fract_part.push_char((digit as u8 + '0' as u8) as char);
            pos -= 1;
        }
    }
    int_part + fract_part + modifier
}

fn pow(n: uint, p: uint) -> uint {
    let mut num = 1;
    for _ in range(0, p) {
        num *= n;
    }
    num
}

fn format_bytes(mut bytes: uint) -> ~str {
    static modifiers: [&'static str, ..4] = ["G", "M", "K", ""];
    let mut i = modifiers.len() - 1;
    while bytes >= 1024 && i != 0 {
        bytes /= 1024;
        i -= 1;
    }
    bytes.to_str() + modifiers[i]
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{format_duration, format_bytes};

    #[test]
    fn test_format_duration() {
        assert_eq!(~"0s", format_duration(0));
        assert_eq!(~"0.009s", format_duration(9));
        assert_eq!(~"0.09s", format_duration(90));
        assert_eq!(~"0.9s", format_duration(900));
        assert_eq!(~"0.999s", format_duration(999));
        assert_eq!(~"1s", format_duration(1000));
        assert_eq!(~"1s", format_duration(1009));
        assert_eq!(~"1.4s", format_duration(1400));
        assert_eq!(~"1.6s", format_duration(1600));
        assert_eq!(~"59s", format_duration(59000));
        assert_eq!(~"1m", format_duration(60000));
        assert_eq!(~"1.5m", format_duration(90000));
        assert_eq!(~"1h", format_duration(60 * 60 * 1000));
        assert_eq!(~"1.5h", format_duration(90 * 60 * 1000));
        assert_eq!(~"10h", format_duration(10 * 60 * 60 * 1000));
    }

    #[test]
    fn test_format_bytes() {
        assert_eq!(~"0", format_bytes(0));
        assert_eq!(~"9", format_bytes(9));
        assert_eq!(~"90", format_bytes(90));
        assert_eq!(~"900", format_bytes(900));
        assert_eq!(~"1000", format_bytes(1000));
        assert_eq!(~"1K", format_bytes(1024));
        assert_eq!(~"2K", format_bytes(2048));
        assert_eq!(~"4K", format_bytes(4096));
        assert_eq!(~"1M", format_bytes(1024 * 1024));
        assert_eq!(~"1G", format_bytes(1024 * 1024 * 1024));
        assert_eq!(~"1024G", format_bytes(1024 * 1024 * 1024 * 1024));
    }
}
<|endoftext|>


<commit_before>use std::path::{PathBuf, Components};
use types::{ToResult, ToError, Bookmark, Bookmarks};
use std::fs::{File};
use std::io::{BufReader, BufWriter, ErrorKind};
use dir::{mkdirp};
use bincode::SizeLimit;
use bincode::rustc_serialize::{encode_into};

// TODO implement display
pub struct Store {
    location: PathBuf,
    // bookmarks: Cell<Bookmarks>, // Maybe?
}

impl Store {
    pub fn new(location: PathBuf) -> Store {
        let mut location = PathBuf::from(location);
                location.push("db.bin");

        println!("location {:?}", location);
        return Store{ location: location };
    }

    pub fn all(&self) -> ToResult<Bookmarks> {
        let collection = match self.read() {
            Ok(value) => value,
            Err(err) => panic!(err),
        };

        return Ok(collection);
    }

    pub fn put(&self, name: String, directory: PathBuf) -> ToResult<()> {
        println!("PUT: {:?} {:?}", name, directory);

        let mut collection = match self.all() {
            Ok(value) => value,
            Err(err) => panic!(err),
        };

        let key = name.clone();
        let value = Bookmark::new(name, directory);
        collection.insert(key, value);

        println!("collection {:?}", collection);

        if let Err(err) = self.write(collection) {
            print!("Error on put");
        }

        return Ok(());
    }

    fn read(&self) -> ToResult<Bookmarks> {
        let file = match open(&self.location) {
            Ok(value) => value,
            Err(err) => return Err(err),
        };

        // let mut reader = BufReader::new(file);
        //
        //
        // println!("reader {:?}", reader);
        // println!("decoded {:?}", decoded);
        //
        let bookmarks = Bookmarks::new();

        return Ok(bookmarks);
    }

            //
            // let mut collection: BTreeMap<String, bookmark::Bookmark> = BTreeMap::new();
            // let key = bm.name.clone();
            // collection.insert(key, bm);
            //
            //
            // let encoded: Vec<u8> = encode(&collection, SizeLimit::Infinite).unwrap();
            //
            // println!("encoded {:?}", encoded);
            //
            // let decoded: BTreeMap<String, bookmark::Bookmark> = decode(&encoded[..]).unwrap();
            //
            // println!("decoded {:?}", decoded["foo"]);

    fn write(&self, bookmarks: Bookmarks) -> ToResult<()> {
        return Ok(());
    }
}

fn open(location: &PathBuf) -> ToResult<File> {
    let directory = match location.parent() {
        Some(value) => value,
        None => panic!("location cannot be a directory."),
    };

    if let Err(err) = mkdirp(directory) {
        return Err(err);
    }

    let file = match File::open(location) {
        Ok(value) => value,
        Err(ref err) if err.kind() == ErrorKind::NotFound => {
            match bootstrap(location) {
                Ok(value) => return Ok(value),
                Err(err) => return Err(err),
            }
        },
        Err(err) => return Err(ToError::Io(err)),
    };

    return Ok(file);
}

fn bootstrap(location: &PathBuf) -> ToResult<File> {
    let file = match File::create(&location) {
        Ok(value) => value,
        Err(err) => return Err(ToError::Io(err)),
    };

    let bookmarks = Bookmarks::new();
    let mut writer = BufWriter::new(file);
    match encode_into(&bookmarks, &mut writer, SizeLimit::Infinite) {
        Ok(_) => println!("successful encode"),
        Err(err) => panic!("ERROR ECODING: {:?}", err),
    }

    match File::open(location) {
        Ok(value) => return Ok(value),
        Err(err) => return Err(ToError::Io(err)),
    };
}
<commit_msg>Broken file writing.<commit_after>use std::path::{PathBuf, Components};
use types::{ToResult, ToError, Bookmark, Bookmarks};
use std::fs::{File};
use std::io::{BufReader, BufWriter, ErrorKind};
use dir::{mkdirp};
use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, encode_into, decode_from};

// TODO implement display
pub struct Store {
    location: PathBuf,
    // bookmarks: Cell<Bookmarks>, // Maybe?
}

impl Store {
    pub fn new(location: PathBuf) -> Store {
        let mut location = PathBuf::from(location);
                location.push("db.bin");

        println!("location {:?}", location);
        return Store{ location: location };
    }

    pub fn all(&self) -> ToResult<Bookmarks> {
        let collection = match self.read() {
            Ok(value) => value,
            Err(err) => panic!(err),
        };

        return Ok(collection);
    }

    pub fn put(&self, name: String, directory: PathBuf) -> ToResult<()> {
        println!("PUT: {:?} {:?}", name, directory);

        let mut collection = match self.all() {
            Ok(value) => value,
            Err(err) => panic!(err),
        };

        let key = name.clone();
        let value = Bookmark::new(name, directory);
        collection.insert(key, value);

        println!("collection {:?}", collection);

        if let Err(err) = self.write(collection) {
            print!("Error on put");
        }

        return Ok(());
    }

    fn read(&self) -> ToResult<Bookmarks> {
        let file = match open(&self.location) {
            Ok(value) => value,
            Err(err) => return Err(err),
        };

        let mut reader = BufReader::new(file);
        let bookmarks: Bookmarks = match decode_from(&mut reader, SizeLimit::Infinite) {
            Ok(value) => value,
            Err(err) => panic!("DECODING ERROR"),
        };

        println!("existing {:?}", bookmarks);

        return Ok(bookmarks);
    }

    fn write(&self, bookmarks: Bookmarks) -> ToResult<()> {
        println!("Writing db to {:?}", self.location);
        println!(" * bookmarks {:?}", bookmarks);

        let file = match open(&self.location) {
            Ok(value) => value,
            Err(err) => return Err(err),
        };

        println!("file {:?}", file);

        let bytes: Vec<u8> = match encode(&bookmarks, SizeLimit::Infinite) {
            Ok(value) => value,
            Err(err) => panic!(err),
        };

        println!("encoded bytes {:?}", bytes);

        match file.write_all(&bytes) {
            Ok(value) => return Ok(value),
            Err(err) => panic!("Error writing encoded DB"),
        }

        return Ok(());
    }
}

fn open(location: &PathBuf) -> ToResult<File> {
    let directory = match location.parent() {
        Some(value) => value,
        None => panic!("location cannot be a directory."),
    };

    if let Err(err) = mkdirp(directory) {
        return Err(err);
    }

    let file = match File::open(location) {
        Ok(value) => value,
        Err(ref err) if err.kind() == ErrorKind::NotFound => {
            match bootstrap(location) {
                Ok(value) => return Ok(value),
                Err(err) => return Err(err),
            }
        },
        Err(err) => return Err(ToError::Io(err)),
    };

    return Ok(file);
}

// TODO: open a new db without wrtiting to it first.
fn bootstrap(location: &PathBuf) -> ToResult<File> {
    println!("bootstrapping {:?}", location);
    let file = match File::create(&location) {
        Ok(value) => value,
        Err(err) => return Err(ToError::Io(err)),
    };

    let bookmarks = Bookmarks::new();
    let mut writer = BufWriter::new(file);
    match encode_into(&bookmarks, &mut writer, SizeLimit::Infinite) {
        Ok(_) => println!("successful encode"),
        Err(err) => panic!("ERROR ECODING: {:?}", err),
    }

    match File::open(location) {
        Ok(value) => return Ok(value),
        Err(err) => return Err(ToError::Io(err)),
    };
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

#[inline]
fn header_parser(input: &[u8]) -> IResult<&[u8], &[u8], ErrorKind> {
  tag!(input, "fLaC").map_err(to_custom_error!(HeaderParser))
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, header_parser);

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add panic test for `power_of_two`<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

#[inline]
fn header_parser(input: &[u8]) -> IResult<&[u8], &[u8], ErrorKind> {
  tag!(input, "fLaC").map_err(to_custom_error!(HeaderParser))
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, header_parser);

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(10));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add documentation for `power_of_two`<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(10));

  if *state == ParserState::Header {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>use config::{Benchmark, parse_config};
use repo::Workspace;

use std::collections::HashMap;
use std::io;
use std::path::Path;
use std::process::{Command, ExitStatus};
use std::str;

/// `(val, percentage_change)`
#[derive(Debug, Clone)]
pub enum BenchmarkResult<T> {
    Improvement(T, f64),
    Regression(T, f64),
    Neutral(T, f64),
}

#[derive(Debug, Clone)]
pub struct TastingResult {
    pub branch: String,
    pub commit_id: String,
    pub commit_msg: String,
    pub commit_url: String,
    pub build: bool,
    pub test: bool,
    pub bench: bool,
    pub results: Option<Vec<HashMap<String, BenchmarkResult<f64>>>>,
}

fn benchmark(workdir: &str,
             cfg: &Benchmark,
             previous_result: Option<&HashMap<String, BenchmarkResult<f64>>>)
             -> (ExitStatus, HashMap<String, BenchmarkResult<f64>>) {
    let mut cmd = Command::new("cargo");
    cmd.current_dir(workdir)
        .env("RUST_BACKTRACE", "1")
        .arg(&cfg.cmd)
        .args(cfg.args.as_slice());

    let output = cmd.output()
        .expect(&format!("Failed to execute benchmark '{}'!", cfg.name));

    let lines = str::from_utf8(output.stdout.as_slice()).unwrap().lines();
    let mut res = HashMap::new();

    // Don't try parsing the output if we didn't succeed
    if !output.status.success() {
        return (output.status, res);
    }

    // Success, so let's look for the results
    for l in lines {
        for (i, regex) in cfg.result_expr.iter().enumerate() {
            for cap in regex.captures_iter(l) {
                let (metric, value) = if cap.len() > 2 {
                    (String::from(cap.at(1).unwrap()), cap.at(2))
                } else {
                    (format!("{}", i), cap.at(1))
                };
                let bm_name = format!("{}/{}", cfg.name, &metric);
                if let Some(c) = value {
                    use std::str::FromStr;
                    let val = match f64::from_str(&c) {
                        Ok(f) => f,
                        Err(_) => {
                            println!("failed to parse value '{}' for {} into f64 number, ignoring",
                                     c,
                                     bm_name);
                            continue;
                        }
                    };
                    let new_result = match previous_result {
                        None => BenchmarkResult::Neutral(val, 0.0),
                        Some(prev_res) => {
                            let old_val = match *prev_res.get(&bm_name).unwrap() {
                                BenchmarkResult::Improvement(v, _) => v,
                                BenchmarkResult::Regression(v, _) => v,
                                BenchmarkResult::Neutral(v, _) => v,
                            };
                            let new_result = if val >= old_val * 1.1 {
                                BenchmarkResult::Improvement(val, (val / old_val) - 1.0)
                            } else if val < old_val * 0.9 {
                                BenchmarkResult::Regression(val, (val / old_val) - 1.0)
                            } else {
                                BenchmarkResult::Neutral(val, (val / old_val) - 1.0)
                            };
                            new_result
                        }
                    };
                    res.insert(bm_name, new_result);
                }
            }
        }
    }
    (output.status, res)
}

fn build(workdir: &str) -> ExitStatus {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("build")
        .arg("--release")
        .env("RUST_BACKTRACE", "1")
        .status()
        .expect("Failed to execute 'cargo build'!")
}

pub fn taste_commit(ws: &Workspace,
                    history: &mut HashMap<String,
                                          HashMap<String, HashMap<String, BenchmarkResult<f64>>>>,
                    commit_ref: &str,
                    id: &str,
                    msg: &str,
                    url: &str)
                    -> Result<TastingResult, String> {
    println!("Tasting commit {}", id);
    ws.checkout_commit(id)?;

    let branch = String::from(&commit_ref[commit_ref.rfind("/").unwrap() + 1..]);

    let build_success = update(&ws.path).success() && build(&ws.path).success();
    let test_success = test(&ws.path).success();

    let cfg = match parse_config(Path::new(&format!("{}/taster.toml", ws.path))) {
        Ok(c) => c,
        Err(e) => {
            match e.kind() {
                io::ErrorKind::NotFound => {
                    println!("Skipping commit {} which doesn't have a Taster config.", id);
                    return Ok(TastingResult {
                        branch: branch,
                        commit_id: String::from(id),
                        commit_msg: String::from(msg),
                        commit_url: String::from(url),
                        build: build_success,
                        test: test_success,
                        bench: false,
                        results: None,
                    });
                }
                _ => unimplemented!(),
            }
        }
    };

    let branch_history = history.entry(branch.clone()).or_insert(HashMap::new());
    let bench_out = cfg.iter()
        .map(|b| {
            let new_result = benchmark(&ws.path, b, branch_history.get(&b.name));
            branch_history.insert(b.name.clone(), new_result.1.clone());
            new_result
        })
        .collect::<Vec<(ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>();
    let bench_success = bench_out.iter().all(|x| x.0.success());
    let bench_results = bench_out.iter().map(|x| x.1.clone()).collect();

    Ok(TastingResult {
        branch: branch,
        commit_id: String::from(id),
        commit_msg: String::from(msg),
        commit_url: String::from(url),
        build: build_success,
        test: test_success,
        bench: bench_success,
        results: Some(bench_results),
    })
}

fn test(workdir: &str) -> ExitStatus {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("test")
        .env("RUST_BACKTRACE", "1")
        .env("RUST_TEST_THREADS", "1")
        .status()
        .expect("Failed to execute 'cargo test'!")
}

fn update(workdir: &str) -> ExitStatus {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("update")
        .status()
        .expect("Failed to execute 'cargo update'!")
}
<commit_msg>Don't crash if a commit has no branch<commit_after>use config::{Benchmark, parse_config};
use repo::Workspace;

use std::collections::HashMap;
use std::io;
use std::path::Path;
use std::process::{Command, ExitStatus};
use std::str;

/// `(val, percentage_change)`
#[derive(Debug, Clone)]
pub enum BenchmarkResult<T> {
    Improvement(T, f64),
    Regression(T, f64),
    Neutral(T, f64),
}

#[derive(Debug, Clone)]
pub struct TastingResult {
    pub branch: String,
    pub commit_id: String,
    pub commit_msg: String,
    pub commit_url: String,
    pub build: bool,
    pub test: bool,
    pub bench: bool,
    pub results: Option<Vec<HashMap<String, BenchmarkResult<f64>>>>,
}

fn benchmark(workdir: &str,
             cfg: &Benchmark,
             previous_result: Option<&HashMap<String, BenchmarkResult<f64>>>)
             -> (ExitStatus, HashMap<String, BenchmarkResult<f64>>) {
    let mut cmd = Command::new("cargo");
    cmd.current_dir(workdir)
        .env("RUST_BACKTRACE", "1")
        .arg(&cfg.cmd)
        .args(cfg.args.as_slice());

    let output = cmd.output()
        .expect(&format!("Failed to execute benchmark '{}'!", cfg.name));

    let lines = str::from_utf8(output.stdout.as_slice()).unwrap().lines();
    let mut res = HashMap::new();

    // Don't try parsing the output if we didn't succeed
    if !output.status.success() {
        return (output.status, res);
    }

    // Success, so let's look for the results
    for l in lines {
        for (i, regex) in cfg.result_expr.iter().enumerate() {
            for cap in regex.captures_iter(l) {
                let (metric, value) = if cap.len() > 2 {
                    (String::from(cap.at(1).unwrap()), cap.at(2))
                } else {
                    (format!("{}", i), cap.at(1))
                };
                let bm_name = format!("{}/{}", cfg.name, &metric);
                if let Some(c) = value {
                    use std::str::FromStr;
                    let val = match f64::from_str(&c) {
                        Ok(f) => f,
                        Err(_) => {
                            println!("failed to parse value '{}' for {} into f64 number, ignoring",
                                     c,
                                     bm_name);
                            continue;
                        }
                    };
                    let new_result = match previous_result {
                        None => BenchmarkResult::Neutral(val, 0.0),
                        Some(prev_res) => {
                            let old_val = match *prev_res.get(&bm_name).unwrap() {
                                BenchmarkResult::Improvement(v, _) => v,
                                BenchmarkResult::Regression(v, _) => v,
                                BenchmarkResult::Neutral(v, _) => v,
                            };
                            let new_result = if val >= old_val * 1.1 {
                                BenchmarkResult::Improvement(val, (val / old_val) - 1.0)
                            } else if val < old_val * 0.9 {
                                BenchmarkResult::Regression(val, (val / old_val) - 1.0)
                            } else {
                                BenchmarkResult::Neutral(val, (val / old_val) - 1.0)
                            };
                            new_result
                        }
                    };
                    res.insert(bm_name, new_result);
                }
            }
        }
    }
    (output.status, res)
}

fn build(workdir: &str) -> ExitStatus {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("build")
        .arg("--release")
        .env("RUST_BACKTRACE", "1")
        .status()
        .expect("Failed to execute 'cargo build'!")
}

pub fn taste_commit(ws: &Workspace,
                    history: &mut HashMap<String,
                                          HashMap<String, HashMap<String, BenchmarkResult<f64>>>>,
                    commit_ref: &str,
                    id: &str,
                    msg: &str,
                    url: &str)
                    -> Result<TastingResult, String> {
    println!("Tasting commit {}", id);
    ws.checkout_commit(id)?;

    let branch = match commit_ref.rfind("/") {
        None => String::from(""),
        Some(i) => String::from(&commit_ref[i + 1..]),
    };

    let build_success = update(&ws.path).success() && build(&ws.path).success();
    let test_success = test(&ws.path).success();

    let cfg = match parse_config(Path::new(&format!("{}/taster.toml", ws.path))) {
        Ok(c) => c,
        Err(e) => {
            match e.kind() {
                io::ErrorKind::NotFound => {
                    println!("Skipping commit {} which doesn't have a Taster config.", id);
                    return Ok(TastingResult {
                        branch: branch,
                        commit_id: String::from(id),
                        commit_msg: String::from(msg),
                        commit_url: String::from(url),
                        build: build_success,
                        test: test_success,
                        bench: false,
                        results: None,
                    });
                }
                _ => unimplemented!(),
            }
        }
    };

    let branch_history = history.entry(branch.clone()).or_insert(HashMap::new());
    let bench_out = cfg.iter()
        .map(|b| {
            let new_result = benchmark(&ws.path, b, branch_history.get(&b.name));
            branch_history.insert(b.name.clone(), new_result.1.clone());
            new_result
        })
        .collect::<Vec<(ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>();
    let bench_success = bench_out.iter().all(|x| x.0.success());
    let bench_results = bench_out.iter().map(|x| x.1.clone()).collect();

    Ok(TastingResult {
        branch: branch,
        commit_id: String::from(id),
        commit_msg: String::from(msg),
        commit_url: String::from(url),
        build: build_success,
        test: test_success,
        bench: bench_success,
        results: Some(bench_results),
    })
}

fn test(workdir: &str) -> ExitStatus {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("test")
        .env("RUST_BACKTRACE", "1")
        .env("RUST_TEST_THREADS", "1")
        .status()
        .expect("Failed to execute 'cargo test'!")
}

fn update(workdir: &str) -> ExitStatus {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("update")
        .status()
        .expect("Failed to execute 'cargo update'!")
}
<|endoftext|>


<commit_before>use ::CanSocket;

#[test]
fn test_nonexistant_device() {
    assert!(CanSocket::open("invalid").is_err());
}

#[cfg(feature = "vcan_tests")]
mod vcan_tests {
    use ::{CanFrame, CanInterface, CanSocket, ERR_MASK_ALL, ERR_MASK_NONE};
    use std::time;
    use ::ShouldRetry;

    #[test]
    fn vcan0_timeout() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_read_timeout(time::Duration::from_millis(100)).unwrap();
        assert!(cs.read_frame().should_retry());
    }

    #[test]
    fn vcan0_set_error_mask() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_error_mask(ERR_MASK_ALL).unwrap();
        cs.set_error_mask(ERR_MASK_NONE).unwrap();
    }

    #[test]
    fn vcan0_enable_own_loopback() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_loopback(true).unwrap();
        cs.set_recv_own_msgs(true).unwrap();

        let frame = CanFrame::new(0x123, &[], true, false).unwrap();

        cs.write_frame(&frame).unwrap();

        cs.read_frame().unwrap();
    }

    #[test]
    fn vcan0_set_down() {
        let can_if = CanInterface::open("vcan0").unwrap();
        can_if.bring_down().unwrap();
    }
}
<commit_msg>Added vcan0 nonblocking test.<commit_after>use CanSocket;

#[test]
fn test_nonexistant_device() {
    assert!(CanSocket::open("invalid").is_err());
}

#[cfg(feature = "vcan_tests")]
mod vcan_tests {
    use {CanFrame, CanInterface, CanSocket, ERR_MASK_ALL, ERR_MASK_NONE};
    use std::time;
    use ShouldRetry;

    #[test]
    fn vcan0_timeout() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_read_timeout(time::Duration::from_millis(100))
            .unwrap();
        assert!(cs.read_frame().should_retry());
    }

    #[test]
    fn vcan0_set_error_mask() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_error_mask(ERR_MASK_ALL).unwrap();
        cs.set_error_mask(ERR_MASK_NONE).unwrap();
    }

    #[test]
    fn vcan0_enable_own_loopback() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_loopback(true).unwrap();
        cs.set_recv_own_msgs(true).unwrap();

        let frame = CanFrame::new(0x123, &[], true, false).unwrap();

        cs.write_frame(&frame).unwrap();

        cs.read_frame().unwrap();
    }

    #[test]
    fn vcan0_set_down() {
        let can_if = CanInterface::open("vcan0").unwrap();
        can_if.bring_down().unwrap();
    }

    #[test]
    fn vcan0_test_nonblocking() {
        let cs = CanSocket::open("vcan0").unwrap();
        cs.set_nonblocking(true);

        // no timeout set, but should return immediately
        assert!(cs.read_frame().should_retry());
    }

}
<|endoftext|>