<commit_before>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

pub use self::signal::{
    SockFlag,

    SA_NOCLDSTOP,
    SA_NOCLDWAIT,
    SA_NODEFER,
    SA_ONSTACK,
    SA_RESETHAND,
    SA_RESTART,
    SA_SIGINFO,
};

pub use self::signal::{HowFlag, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK};
pub use self::signal::sigset_t;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "aarch64",
                  target_arch = "arm")),
          target_os = "android"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_ulong {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00000002,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000004,
        }
    );

    bitflags!{
        flags HowFlag: libc::c_int {
            const SIG_BLOCK   = 0,
            const SIG_UNBLOCK = 1,
            const SIG_SETMASK = 2,
        }
    }

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    #[allow(missing_copy_implementations)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
        sa_restorer: *mut libc::c_void,
    }

    #[repr(C)]
    #[cfg(target_pointer_width = "32")]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 32],
    }

    #[repr(C)]
    #[cfg(target_pointer_width = "64")]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_uint {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00001000,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000008,
        }
    );

    bitflags!{
        flags HowFlag: libc::c_int {
            const SIG_BLOCK   = 1,
            const SIG_UNBLOCK = 2,
            const SIG_SETMASK = 3,
        }
    }

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_code: libc::c_int,
        pub si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: SockFlag,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int; 1],
    }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong; 32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_int {
            const SA_NOCLDSTOP = 0x0008,
            const SA_NOCLDWAIT = 0x0020,
            const SA_NODEFER   = 0x0010,
            const SA_ONSTACK   = 0x0001,
            const SA_RESETHAND = 0x0004,
            const SA_RESTART   = 0x0002,
            const SA_SIGINFO   = 0x0040,
        }
    );

    bitflags!{
        flags HowFlag: libc::c_int {
            const SIG_BLOCK   = 1,
            const SIG_UNBLOCK = 2,
            const SIG_SETMASK = 3,
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
    pub type sigset_t = u32;
    #[cfg(target_os = "freebsd")]
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        bits: [u32; 4],
    }
    #[cfg(any(target_os = "dragonfly", target_os = "netbsd"))]
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct sigset_t {
        bits: [libc::c_uint; 4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[cfg(not(target_os = "dragonfly"))]
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[cfg(target_os = "dragonfly")]
    #[repr(C)]
    #[derive(Clone, Copy)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::c_int,
        pub uid: libc::c_uint,
        pub status: libc::c_int,
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    #[repr(C)]
    #[allow(missing_copy_implementations)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: SockFlag,
        pub sa_mask: sigset_t,
    }

    #[cfg(any(target_os = "openbsd", target_os = "netbsd"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }
}

mod ffi {
    use libc::{c_int, pid_t};
    use super::signal::{sigaction, sigset_t};

    #[allow(improper_ctypes)]
    extern {
        pub fn sigaction(signum: c_int,
                         act: *const sigaction,
                         oldact: *mut sigaction) -> c_int;

        pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int;
        pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int;
        pub fn sigemptyset(set: *mut sigset_t) -> c_int;
        pub fn sigfillset(set: *mut sigset_t) -> c_int;
        pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int;

        pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int;

        pub fn kill(pid: pid_t, signum: c_int) -> c_int;
        pub fn raise(signum: c_int) -> c_int;

        pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int;
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { ffi::sigfillset(&mut sigset as *mut sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { ffi::sigaddset(&mut self.sigset as *mut sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { ffi::sigdelset(&mut self.sigset as *mut sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { ffi::sigismember(&self.sigset as *const sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(HowFlag::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: HowFlag) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { ffi::sigwait(&self.sigset as *const sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<sigset_t> for SigSet {
    fn as_ref(&self) -> &sigset_t {
        &self.sigset
    }
}

pub use self::signal::siginfo;

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut siginfo, *mut libc::c_void))
}

type sigaction_t = self::signal::sigaction;

pub struct SigAction {
    sigaction: sigaction_t
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SockFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<sigaction_t>() };
        s.sa_handler = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => f,
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => flags | SA_SIGINFO,
            _ => flags - SA_SIGINFO,
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<sigaction_t>();

    let res =
        ffi::sigaction(signum, &sigaction.sigaction as *const sigaction_t, &mut oldact as *mut sigaction_t);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: HowFlag,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        ffi::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<sigset_t>(),
                                             |s| &s.sigset as *const sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<sigset_t>(),
                                                |os| &mut os.sigset as *mut sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { ffi::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { ffi::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(signal::SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<commit_msg>Auto merge of #285 - fiveop:use_libc, r=@kamalmarhubi<commit_after>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlag: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlag: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

mod ffi {
    use libc;
    extern {
        pub fn sigwait(set: *const libc::sigset_t, sig: *mut libc::c_int) -> libc::c_int;
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlag::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlag) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { ffi::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[allow(raw_pointer_derive)]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlag,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<|endoftext|>


<commit_before>///! fff-lang
///!
///! syntax/module, a source code file is a module
///! module = { item }

use std::fmt;
use std::rc::Rc;

use codemap::SourceCode;
use lexical::Token;

use super::super::Item;
use super::super::ImportStatement;

use super::super::Formatter;
use super::super::ParseResult;
use super::super::ParseSession;
use super::super::ISyntaxParse;
use super::super::ISyntaxFormat;
use super::super::ISyntaxGrammar;

#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct Module {
    pub items: Vec<Item>,
    pub source: Rc<SourceCode>,
}
impl ISyntaxFormat for Module {
    fn format(&self, f: Formatter) -> String {
        let mut f = f.indent().header_text_or("module").endl()
            .indent1().debug(self.source.as_ref());
        if self.items.len() == 0 {
            f = f.endl().indent1().lit("no-item");
        }
        for item in &self.items {
            f = f.endl().apply1(item);
        }
        f.finish()
    }
}
impl fmt::Debug for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\n{}", self.format(Formatter::empty())) }
}
impl Module {
    pub fn new(source: Rc<SourceCode>, items: Vec<Item>) -> Module { Module{ source, items } }

    // TODO: update to `impl Iterator<Item = Item>` and remove collect after stabilize
    pub fn import_statements(&self) -> Vec<&ImportStatement> {
        self.items.iter()
            .map(|ref item| if let &&Item::Import(ref import_stmt) = item { Some(import_stmt) } else { None })
            .filter(|maybe_import| maybe_import.is_some())
            .map(|maybe_import| maybe_import.unwrap())
            .collect()
    }
}
impl ISyntaxParse for Module {
    type Output = Module;

    fn parse(sess: &mut ParseSession) -> ParseResult<Module> {
        let mut items = Vec::new();
        loop {
            if Item::matches_first(sess.current_tokens()) {
                items.push(Item::parse(sess)?);
            } else if sess.current_tokens()[0] == &Token::EOF { // as module is special, specially allow self.current_tokens in parse
                break;
            } else {
                return sess.push_unexpect("if, while, for, var, const, expr");
            }
        }
        return Ok(Module::new(sess.source.clone(), items));
    }
}

#[cfg(test)] #[test]
fn module_parse() {
    use codemap::Span;
    use codemap::SymbolCollection;
    use lexical::LitValue;
    use super::super::TestInput;
    use super::super::UseStatement;
    use super::super::Name;
    use super::super::SimpleName;
    use super::super::ImportStatement;
    use super::super::SimpleExprStatement;
    use super::super::LitExpr;

    //              0123456789012345678901234
    TestInput::new("use a; import b; 3; b; a;")
        .set_syms(make_symbols!["a", "b"])
        .apply::<Module, _>()
        .expect_no_message()
        .expect_result(Module::new(
            Rc::new(SourceCode::with_test_str(0, "use a; import b; 3; b; a;")), vec![
            Item::Use(UseStatement::new_default(make_span!(0, 5),
                Name::new(make_span!(4, 4), vec![
                    SimpleName::new(make_id!(1), make_span!(4, 4))
                ])
            )),
            Item::Import(ImportStatement::new_default(make_span!(7, 15),
                SimpleName::new(make_id!(2), make_span!(14, 14))
            )),
            Item::SimpleExpr(SimpleExprStatement::new(make_span!(17, 18),
                LitExpr::new(LitValue::from(3), make_span!(17, 17))
            )),
            Item::SimpleExpr(SimpleExprStatement::new(make_span!(20, 21),
                SimpleName::new(make_id!(2), make_span!(20, 20))
            )),
            Item::SimpleExpr(SimpleExprStatement::new(make_span!(23, 24),
                SimpleName::new(make_id!(1), make_span!(23, 23))
            )),
        ]))
    .finish();
}

#[cfg(test)] #[test]
fn module_integration() {
    use std::fs::File;
    use std::io::Read;
    use super::super::TestInput;

    let mut index_file = File::open("../tests/syntax/inter/index.txt").expect("cannot open index.txt");
    let mut test_cases = String::new();
    let _length = index_file.read_to_string(&mut test_cases).expect("cannot read index.txt");
    for line in test_cases.lines() {
        let src_path = "../tests/syntax/inter/".to_owned() + line + "_src.ff";
        let mut src_file = File::open(&src_path).expect(&format!("cannot open src file {}", src_path));
        let mut src = String::new();
        let _length = src_file.read_to_string(&mut src).expect(&format!("cannot read src file {}", src_path));
        let result_path = "../tests/syntax/inter/".to_owned() + line + "_result.txt";
        let mut result_file = File::open(&result_path).expect(&format!("cannot open result file {}", result_path));
        let mut expect = String::new();
        let _length = result_file.read_to_string(&mut expect).expect(&format!("cannot read result file {}", result_path));

        let result = TestInput::new(&src).apply::<Module, _>().expect_no_message();
        let actual = result.get_result().unwrap().format(Formatter::new(Some(result.get_source()), Some(result.get_symbols())));
        if actual != expect {
            panic!("case '{}' failed, actual:\n`{}`\nexpect:\n`{}`", line, actual, expect)
        }
    }
}<commit_msg>[syntax] update module integration test for precise panic info<commit_after>///! fff-lang
///!
///! syntax/module, a source code file is a module
///! module = { item }

use std::fmt;
use std::rc::Rc;

use codemap::SourceCode;
use lexical::Token;

use super::super::Item;
use super::super::ImportStatement;

use super::super::Formatter;
use super::super::ParseResult;
use super::super::ParseSession;
use super::super::ISyntaxParse;
use super::super::ISyntaxFormat;
use super::super::ISyntaxGrammar;

#[cfg_attr(test, derive(Eq, PartialEq))]
pub struct Module {
    pub items: Vec<Item>,
    pub source: Rc<SourceCode>,
}
impl ISyntaxFormat for Module {
    fn format(&self, f: Formatter) -> String {
        let mut f = f.indent().header_text_or("module").endl()
            .indent1().debug(self.source.as_ref());
        if self.items.len() == 0 {
            f = f.endl().indent1().lit("no-item");
        }
        for item in &self.items {
            f = f.endl().apply1(item);
        }
        f.finish()
    }
}
impl fmt::Debug for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\n{}", self.format(Formatter::empty())) }
}
impl Module {
    pub fn new(source: Rc<SourceCode>, items: Vec<Item>) -> Module { Module{ source, items } }

    // TODO: update to `impl Iterator<Item = Item>` and remove collect after stabilize
    pub fn import_statements(&self) -> Vec<&ImportStatement> {
        self.items.iter()
            .map(|ref item| if let &&Item::Import(ref import_stmt) = item { Some(import_stmt) } else { None })
            .filter(|maybe_import| maybe_import.is_some())
            .map(|maybe_import| maybe_import.unwrap())
            .collect()
    }
}
impl ISyntaxParse for Module {
    type Output = Module;

    fn parse(sess: &mut ParseSession) -> ParseResult<Module> {
        let mut items = Vec::new();
        loop {
            if Item::matches_first(sess.current_tokens()) {
                items.push(Item::parse(sess)?);
            } else if sess.current_tokens()[0] == &Token::EOF { // as module is special, specially allow self.current_tokens in parse
                break;
            } else {
                return sess.push_unexpect("if, while, for, var, const, expr");
            }
        }
        return Ok(Module::new(sess.source.clone(), items));
    }
}

#[cfg(test)] #[test]
fn module_parse() {
    use codemap::Span;
    use codemap::SymbolCollection;
    use lexical::LitValue;
    use super::super::TestInput;
    use super::super::UseStatement;
    use super::super::Name;
    use super::super::SimpleName;
    use super::super::ImportStatement;
    use super::super::SimpleExprStatement;
    use super::super::LitExpr;

    //              0123456789012345678901234
    TestInput::new("use a; import b; 3; b; a;")
        .set_syms(make_symbols!["a", "b"])
        .apply::<Module, _>()
        .expect_no_message()
        .expect_result(Module::new(
            Rc::new(SourceCode::with_test_str(0, "use a; import b; 3; b; a;")), vec![
            Item::Use(UseStatement::new_default(make_span!(0, 5),
                Name::new(make_span!(4, 4), vec![
                    SimpleName::new(make_id!(1), make_span!(4, 4))
                ])
            )),
            Item::Import(ImportStatement::new_default(make_span!(7, 15),
                SimpleName::new(make_id!(2), make_span!(14, 14))
            )),
            Item::SimpleExpr(SimpleExprStatement::new(make_span!(17, 18),
                LitExpr::new(LitValue::from(3), make_span!(17, 17))
            )),
            Item::SimpleExpr(SimpleExprStatement::new(make_span!(20, 21),
                SimpleName::new(make_id!(2), make_span!(20, 20))
            )),
            Item::SimpleExpr(SimpleExprStatement::new(make_span!(23, 24),
                SimpleName::new(make_id!(1), make_span!(23, 23))
            )),
        ]))
    .finish();
}

#[cfg(test)] #[test]
fn module_integration() {
    use std::fs::File;
    use std::io::Read;
    use super::super::TestInput;

    let mut index_file = File::open("../tests/syntax/inter/index.txt").expect("cannot open index.txt");
    let mut test_cases = String::new();
    let _length = index_file.read_to_string(&mut test_cases).expect("cannot read index.txt");
    for line in test_cases.lines() {
        let src_path = "../tests/syntax/inter/".to_owned() + line + "_src.ff";
        let mut src_file = File::open(&src_path).expect(&format!("cannot open src file {}", src_path));
        let mut src = String::new();
        let _length = src_file.read_to_string(&mut src).expect(&format!("cannot read src file {}", src_path));
        let result_path = "../tests/syntax/inter/".to_owned() + line + "_result.txt";
        let mut result_file = File::open(&result_path).expect(&format!("cannot open result file {}", result_path));
        let mut expect = String::new();
        let _length = result_file.read_to_string(&mut expect).expect(&format!("cannot read result file {}", result_path));
        let expect = expect.replace("\r\n", "\n");

        let result = TestInput::new(&src).apply::<Module, _>().expect_no_message();
        let actual = result.get_result().unwrap().format(Formatter::new(Some(result.get_source()), Some(result.get_symbols())));
        if actual != expect {
            println!("case '{}' failed:", line);
            for (linenum, (actual_line, expect_line)) in actual.split_terminator('\n').zip(expect.split_terminator('\n')).enumerate() {
                if actual_line == expect_line {
                    println!("={}) {}", linenum, actual_line);
                } else {
                    println!("x{}) {:?}", linenum, actual_line);
                    println!("x{}) {:?}", linenum, expect_line);
                }
            }
            panic!("case failed")
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2015 Jameson Ernst
// 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.

//! Abstraction of a thread pool for basic parallelism.
//! Modified to prevent blocking: If no threads are
//! currently available to execute the job, a new thread
//! will be created on demand.
//! Modified to

use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::Arc;
use std::thread;
use spin::Mutex;

trait FnBox
{
    fn call_box(self: Box<Self>);
}
impl<F: FnOnce()> FnBox for F
{
    fn call_box(self: Box<F>)
    {
        (*self)()
    }
}

type Thunk<'a> = Box<FnBox + Send + 'a>;

struct Sentinel<'a>
{
    jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>,
    active: bool
}
impl<'a> Sentinel<'a>
{
    fn new(jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>) -> Sentinel<'a> {
        Sentinel {
            jobs: jobs,
            active: true
        }
    }

    fn cancel(mut self) {
        self.active = false;
    }
}
impl<'a> Drop for Sentinel<'a>
{
    fn drop(&mut self)
    {
        if self.active {
            spawn_in_pool(self.jobs.clone())
        }
    }
}

#[derive(Clone)]
pub struct ThreadPool
{
    jobs: Sender<Thunk<'static>>
}
impl ThreadPool
{
    pub fn new(threads: usize) -> ThreadPool
    {
        assert!(threads >= 1);

        let (tx, rx) = channel::<Thunk<'static>>();
        let rx = Arc::new(Mutex::new(rx));

        for _ in 0..threads {
            spawn_in_pool(rx.clone());
        }

        ThreadPool { jobs: tx }
    }

    pub fn execute<F>(&self, job: F)
        where F : FnOnce() + Send + 'static
    {
        self.jobs.send(Box::new(move || job())).unwrap();
    }
}

fn spawn_in_pool(jobs: Arc<Mutex<Receiver<Thunk<'static>>>>)
{
    thread::spawn(move || {
        let sentinel = Sentinel::new(&jobs);

        loop {
            let message = {
                let lock = jobs.lock();
                lock.recv()
            };

            match message {
                Ok(job) => job.call_box(),
                Err(..) => break,
            }
        }

        sentinel.cancel();
    });
}

<commit_msg>finish threadpool<commit_after>// Copyright 2015 Jameson Ernst
//
// 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.

//! Abstraction of a thread pool for basic parallelism.
//! Modified to prevent blocking: If no threads are
//! currently available to execute the job, a new thread
//! will be created on demand.

use std::sync::mpsc::{sync_channel, SyncSender, Receiver, TrySendError};
use std::sync::{Arc, Mutex};
use std::thread;

trait FnBox
{
    fn call_box(self: Box<Self>);
}
impl<F: FnOnce()> FnBox for F
{
    fn call_box (self: Box<F>)
    {
        (*self)()
    }
}

type Thunk<'a> = Box<FnBox + Send + 'a>;

struct Sentinel<'a>
{
    jobs: &'a Arc<Mutex<Receiver<Thunk<'static>>>>,
    active: bool
}
impl<'a> Sentinel<'a>
{
    fn new (jobs : &'a Arc<Mutex<Receiver<Thunk<'static>>>>) -> Sentinel<'a> {
        Sentinel {
            jobs: jobs,
            active: true
        }
    }

    fn cancel (mut self) {
        self.active = false;
    }
}
impl<'a> Drop for Sentinel<'a>
{
    fn drop (&mut self)
    {
        if self.active {
            spawn_in_pool(self.jobs.clone())
        }
    }
}

#[derive(Clone)]
pub struct ThreadPool
{
    jobs: SyncSender<Thunk<'static>>
}
impl ThreadPool
{
    pub fn new (threads : usize) -> ThreadPool
    {
        assert!(threads >= 1);

        let (tx, rx) = sync_channel::<Thunk<'static>>(threads);
        let rx = Arc::new(Mutex::new(rx));

        for _ in 0..threads {
            spawn_in_pool(rx.clone());
        }

        ThreadPool { jobs: tx }
    }

    pub fn execute <F> (&self, job: F)
        where F : FnOnce() + Send + 'static
    {
        let job = Box::new(move|| job());
        match self.jobs.try_send(job) {
            Err(TrySendError::Full(job)) => { thread::spawn(|| job.call_box()); },
            Err(..) => panic!(),
            Ok(..) => (),
        }
    }
}

fn spawn_in_pool (jobs : Arc<Mutex<Receiver<Thunk<'static>>>>)
{
    thread::spawn (move|| {
        let sentinel = Sentinel::new(&jobs);

        loop {
            let job = {
                let lock = jobs.lock().unwrap();
                lock.recv()
            };
            match job {
                Ok(job) => job.call_box(),
                Err(..) => break,
            }
        }

        sentinel.cancel();
    });
}

<|endoftext|>


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

use rustc_serialize::json::{Json, ToJson, Array};
use {Pos, GeoJsonResult};

/// Ring
#[derive(RustcEncodable, Clone, Debug)]
pub struct Ring(pub Vec<Pos>);

impl ToJson for Ring {
    fn to_json(&self) -> Json {
       let &Ring(ref points) = self;
        points.to_json()
    }
}

impl Ring {
    pub fn from_json(json_ring: &Array) -> GeoJsonResult<Ring> {
        let mut vec = vec![];
        for json_pos in json_ring {
            vec.push(try!(Pos::from_json(expect_array!(json_pos))));
        }
        return Ok(Ring(vec));
    }
}
<commit_msg>Improve documentation for types::ring::Ring<commit_after>// Copyright 2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rustc_serialize::json::{Json, ToJson, Array};
use {Pos, GeoJsonResult};

/// Ring (alias for LinearRing)
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
#[derive(RustcEncodable, Clone, Debug)]
pub struct Ring(pub Vec<Pos>);

impl ToJson for Ring {
    fn to_json(&self) -> Json {
       let &Ring(ref points) = self;
        points.to_json()
    }
}

impl Ring {
    pub fn from_json(json_ring: &Array) -> GeoJsonResult<Ring> {
        let mut vec = vec![];
        for json_pos in json_ring {
            vec.push(try!(Pos::from_json(expect_array!(json_pos))));
        }
        return Ok(Ring(vec));
    }
}
<|endoftext|>


<commit_before>use sha2::{Sha512, Digest};
use std::fmt;
use std::fs::File;
use std::io::{ BufReader, Read };
use std::path::Path;

use error::PackageError;

/// This struct represents the hash result.
pub struct Hash(Box<[u8]>);

impl Hash {
    /// Calculates the SHA-512 of a file.
    /// Returns `Box<[u8]>` if there are no errors during the process of
    /// calculation.
    fn sha2<P: AsRef<Path>>(path: P) -> Result<Hash, PackageError> {
        // Create a SHA512 hasher.
        let mut hasher = Sha512::default();
        // Read the file from `path`
        let file = File::open(path)?;
        let file = BufReader::new(file);
        // Hash the bytes read from the file
        for byte in file.bytes() { hasher.input(&[byte?]) };
        // Return the result (it needs to copy 64 bytes though, ouch)
        Ok(Hash(Box::from(hasher.result().as_slice())))
    }
}

impl fmt::Display for Hash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let &Hash(ref hash) = self;
        let mut content = String::new();
        for &h in hash.as_ref() {
            content += &format!("{:x}", h)
        };
        write!(f, "{}", content)
    }
}

impl<'a> From<&'a str> for Hash {
    fn from(s: &'a str) -> Self {
        // A simple function which converts hexadecimal chars into `u8`s.
        let hex_to_dec = |x| match x {
            b'0'...b'9' => x - b'0',
            y @ b'a'...b'f' => 10 + y - b'a',
            _ => panic!("unable to convert hexadecimal string into decimals"),
        };

        let mut result = Vec::with_capacity(64);
        for x in 1 .. 64+1 {
            let (front, _) = s.split_at(2 * x);
            result.push(
                hex_to_dec(front.as_bytes()[0]) * 16 +
                hex_to_dec(front.as_bytes()[1])
            );
        }

        Hash(result.into_boxed_slice())
    }
}<commit_msg>Serde for Hash<commit_after>use sha2::{Sha512, Digest};
use std::fmt;
use std::fs::File;
use std::io::{ BufReader, Read };
use std::path::Path;

use error::PackageError;

/// This struct represents the hash result.
#[derive(Deserialize, Serialize)]
pub struct Hash(Box<[u8]>);

impl Hash {
    /// Calculates the SHA-512 of a file.
    /// Returns `Box<[u8]>` if there are no errors during the process of
    /// calculation.
    fn sha2<P: AsRef<Path>>(path: P) -> Result<Hash, PackageError> {
        // Create a SHA512 hasher.
        let mut hasher = Sha512::default();
        // Read the file from `path`
        let file = File::open(path)?;
        let file = BufReader::new(file);
        // Hash the bytes read from the file
        for byte in file.bytes() { hasher.input(&[byte?]) };
        // Return the result (it needs to copy 64 bytes though, ouch)
        Ok(Hash(Box::from(hasher.result().as_slice())))
    }
}

impl fmt::Display for Hash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let &Hash(ref hash) = self;
        let mut content = String::new();
        for &h in hash.as_ref() {
            content += &format!("{:x}", h)
        };
        write!(f, "{}", content)
    }
}

impl<'a> From<&'a str> for Hash {
    fn from(s: &'a str) -> Self {
        // A simple function which converts hexadecimal chars into `u8`s.
        let hex_to_dec = |x| match x {
            b'0'...b'9' => x - b'0',
            y @ b'a'...b'f' => 10 + y - b'a',
            _ => panic!("unable to convert hexadecimal string into decimals"),
        };

        let mut result = Vec::with_capacity(64);
        for x in 1 .. 64+1 {
            let (front, _) = s.split_at(2 * x);
            result.push(
                hex_to_dec(front.as_bytes()[0]) * 16 +
                hex_to_dec(front.as_bytes()[1])
            );
        }

        Hash(result.into_boxed_slice())
    }
}<|endoftext|>


<commit_before>use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Display;
use std::clone::Clone;

#[cfg(feature = "inclusive_range")]
use std::ops::RangeInclusive;

/// Enforce that a `String` is minimum `min` characters long.
pub fn min(min: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() >= min {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain less characters than %1.".to_string(),
                args: vec![min.to_string()],
            })
        }
    })
}

/// Enforce that a `String` is maximum `max` characters long.
pub fn max(max: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() <= max {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain more characters than %1.".to_string(),
                args: vec![max.to_string()],
            })
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(mi: usize, ma: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(range: RangeInclusive<usize>) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
pub fn range<T: 'static + PartialOrd + Display + Clone>(a: T,
                                                        b: T)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        if *s >= a && *s <= b {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must be in the range %1..%2.".to_string(),
                args: vec![a.to_string(), b.to_string()],
            })
        }
    })
}

#[cfg(feature = "inclusive_range")]
pub fn range<T: 'static + PartialOrd + Display + Clone>(range: RangeInclusive<T>)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                if *s >= *start && *s <= *end {
                    Ok(())
                } else {
                    Err(::Invalid {
                        msg: "Must be in the range %1..%2.".to_string(),
                        args: vec![start.to_string(), end.to_string()],
                    })
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

/// Enforce that a string must contain `needle`.
pub fn contains(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that `T` must equal `value`.
pub fn eq<T: 'static>(value: T) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display
{
    Box::new(move |s: &T| {
        if *s == value {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Does not equal %1.".to_string(),
                args: vec![value.to_string()],
            })
        }
    })
}

/// Enforce that `T` equals any of the values in `values`.
pub fn either<T: 'static>(values: Vec<T>) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display + Clone
{
    Box::new(move |s: &T| {
        let x = values.iter().find(|x| *x == s);
        let r = x.is_some();
        if r == true {
            Ok(())
        } else {
            let list = values.iter()
                .cloned()
                .fold(String::new(), |acc, v| format!("{}, {}", acc, v));
            Err(::Invalid {
                msg: "Must be one of %1.".to_string(),
                args: vec![list.to_string()],
            })
        }
    })
}

#[cfg(test)]
mod tests {
    use validators::{length, range};

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_length() {
        assert!(length(3...5)(&"12".to_string()).is_err());
        assert!(length(3...5)(&"123".to_string()).is_ok());
        assert!(length(3...5)(&"1234".to_string()).is_ok());
        assert!(length(3...5)(&"12345".to_string()).is_ok());
        assert!(length(3...5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_length() {
        assert!(length(3, 5)(&"12".to_string()).is_err());
        assert!(length(3, 5)(&"123".to_string()).is_ok());
        assert!(length(3, 5)(&"1234".to_string()).is_ok());
        assert!(length(3, 5)(&"12345".to_string()).is_ok());
        assert!(length(3, 5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_range() {
        assert!(range(12...127)(&11).is_err());
        assert!(range(12...127)(&12).is_ok());
        assert!(range(12...127)(&50).is_ok());
        assert!(range(12...127)(&127).is_ok());
        assert!(range(12...127)(&128).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_range() {
        assert!(range(12, 127)(&11).is_err());
        assert!(range(12, 127)(&12).is_ok());
        assert!(range(12, 127)(&50).is_ok());
        assert!(range(12, 127)(&127).is_ok());
        assert!(range(12, 127)(&128).is_err());
    }
}
<commit_msg>Added not_contain validator<commit_after>use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Display;
use std::clone::Clone;

#[cfg(feature = "inclusive_range")]
use std::ops::RangeInclusive;

/// Enforce that a `String` is minimum `min` characters long.
pub fn min(min: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() >= min {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain less characters than %1.".to_string(),
                args: vec![min.to_string()],
            })
        }
    })
}

/// Enforce that a `String` is maximum `max` characters long.
pub fn max(max: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() <= max {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain more characters than %1.".to_string(),
                args: vec![max.to_string()],
            })
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(mi: usize, ma: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(range: RangeInclusive<usize>) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
pub fn range<T: 'static + PartialOrd + Display + Clone>(a: T,
                                                        b: T)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        if *s >= a && *s <= b {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must be in the range %1..%2.".to_string(),
                args: vec![a.to_string(), b.to_string()],
            })
        }
    })
}

#[cfg(feature = "inclusive_range")]
pub fn range<T: 'static + PartialOrd + Display + Clone>(range: RangeInclusive<T>)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                if *s >= *start && *s <= *end {
                    Ok(())
                } else {
                    Err(::Invalid {
                        msg: "Must be in the range %1..%2.".to_string(),
                        args: vec![start.to_string(), end.to_string()],
                    })
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

/// Enforce that a string must contain `needle`.
pub fn contains(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that a string must not contain `needle`.
pub fn not_contain(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if !s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that `T` must equal `value`.
pub fn eq<T: 'static>(value: T) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display
{
    Box::new(move |s: &T| {
        if *s == value {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Does not equal %1.".to_string(),
                args: vec![value.to_string()],
            })
        }
    })
}

/// Enforce that `T` equals any of the values in `values`.
pub fn either<T: 'static>(values: Vec<T>) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display + Clone
{
    Box::new(move |s: &T| {
        let x = values.iter().find(|x| *x == s);
        let r = x.is_some();
        if r == true {
            Ok(())
        } else {
            let list = values.iter()
                .cloned()
                .fold(String::new(), |acc, v| format!("{}, {}", acc, v));
            Err(::Invalid {
                msg: "Must be one of %1.".to_string(),
                args: vec![list.to_string()],
            })
        }
    })
}

#[cfg(test)]
mod tests {
    use validators::{length, range};

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_length() {
        assert!(length(3...5)(&"12".to_string()).is_err());
        assert!(length(3...5)(&"123".to_string()).is_ok());
        assert!(length(3...5)(&"1234".to_string()).is_ok());
        assert!(length(3...5)(&"12345".to_string()).is_ok());
        assert!(length(3...5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_length() {
        assert!(length(3, 5)(&"12".to_string()).is_err());
        assert!(length(3, 5)(&"123".to_string()).is_ok());
        assert!(length(3, 5)(&"1234".to_string()).is_ok());
        assert!(length(3, 5)(&"12345".to_string()).is_ok());
        assert!(length(3, 5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_range() {
        assert!(range(12...127)(&11).is_err());
        assert!(range(12...127)(&12).is_ok());
        assert!(range(12...127)(&50).is_ok());
        assert!(range(12...127)(&127).is_ok());
        assert!(range(12...127)(&128).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_range() {
        assert!(range(12, 127)(&11).is_err());
        assert!(range(12, 127)(&12).is_ok());
        assert!(range(12, 127)(&50).is_ok());
        assert!(range(12, 127)(&127).is_ok());
        assert!(range(12, 127)(&128).is_err());
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::collections::HashMap;
use std::io::Read;
use std::env;

use url::{Url, form_urlencoded};
use url::percent_encoding::percent_decode;
use format::Format;
use reqwest::{self as request, StatusCode, Client};

#[derive(Serialize, Deserialize, Default)]
pub struct VideoInfo {
    pub id: String,
    pub describe: String,
    pub formats: Vec<Format>,
    pub keywords: Vec<String>,
    pub author: String,
    pub duration: i32,
}

impl VideoInfo {
    pub fn get_download_url(&self, f: &Format) -> Result<Url, Box<Error>> {
        let sig = f.meta.get("sig").map(|s| s.as_str()).unwrap_or_default();
        let url_str = if let Some(u) = f.meta.get("url") {
            u.as_str()
        } else {
            return Err(From::from("couldn't extract url from format"));
        };

        let url_str = percent_decode(url_str.as_bytes()).decode_utf8()?.into_owned();
        let mut parse_url = Url::parse(&url_str)?;
        parse_url.query_pairs_mut().append_pair("ratebypass", "yes");
        if !sig.is_empty() {
            parse_url.query_pairs_mut().append_pair("signature", sig);
        }

        Ok(parse_url)
    }
}

const YOUTUBE_VIDEO_INFO_URL: &str = "https://www.youtube.com/get_video_info";

pub fn get_video_info(value: &str) -> Result<VideoInfo, Box<Error>> {
    let parse_url = match Url::parse(value) {
        Ok(u) => u,
        Err(_) => {
            return get_video_info_from_html(value);
        },
    };

    if parse_url.host_str() == Some("youtu.be") {
        return get_video_info_from_short_url(&parse_url);
    }

    get_video_info_from_url(&parse_url)
}

fn get_video_info_from_url(u: &Url) -> Result<VideoInfo, Box<Error>> {
    if let Some(video_id) = u.query_pairs().into_owned().collect::<HashMap<String, String>>().get("v") {
        return get_video_info_from_html(video_id);
    }
    Err(From::from("invalid youtube url, no video id"))
}

fn get_video_info_from_short_url(u: &Url) -> Result<VideoInfo, Box<Error>> {
    let path = u.path().trim_left_matches("/");
    if path.len() > 0 {
        return get_video_info_from_html(path);
    }

    Err(From::from("could not parse short URL"))
}

fn get_video_info_from_html(id: &str) -> Result<VideoInfo, Box<Error>> {
    let info_url = format!("{}?video_id={}", YOUTUBE_VIDEO_INFO_URL, id);
    debug!("{}", info_url);
    let mut resp = get_client()?.get(info_url.as_str())?.send()?;
    if resp.status() != StatusCode::Ok {
        return Err(From::from("video info response invalid status code"));
    }

    let mut info = String::new();
    resp.read_to_string(&mut info)?;
    let info = parse_query(info);
    let mut video_info: VideoInfo = Default::default();
    match info.get("status") {
        Some(s) => {
            if s == "fail" {
                return Err(From::from(format!(
                    "Error {}:{}",
                    info.get("errorcode").map(|s| s.as_str()).unwrap_or_default(),
                    info.get("reason").map(|s| s.as_str()).unwrap_or_default()
                )));
            }
        },
        None => {
            return Err(From::from("get video info, status not found"));
        }
    };

    if let Some(author) = info.get("author") {
        video_info.author = author.to_string();
    } else {
        debug!("unable to extract author");
    }

    if let Some(length) = info.get("length_seconds") {
        video_info.duration = length.parse::<i32>().unwrap_or_default();
    } else {
        debug!("unable to parse duration string");
    }

    if let Some(keywords) = info.get("keywords") {
        video_info.keywords = keywords.split(",").map(|s| s.to_string()).collect();
    } else {
        debug!("unable to extract keywords")
    }

    let mut format_strings = vec![];
    if let Some(fmt_stream) = info.get("url_encoded_fmt_stream_map") {
        format_strings.append(&mut fmt_stream.split(",").collect())
    }

    if let Some(adaptive_fmts) = info.get("adaptive_fmts") {
        format_strings.append(&mut adaptive_fmts.split(",").collect());
    }

    let mut formats: Vec<Format> = vec![];
    for v in &format_strings {
        let query = parse_query(v.to_string());
        let itag = match query.get("itag") {
            Some(i) => i,
            None => {
                continue;
            }
        };

        if let Ok(i) = itag.parse::<i32>() {
            if let Some(mut f) = Format::new(i) {
                if query.get("conn").map(|s| s.as_str()).unwrap_or_default().starts_with("rtmp") {
                    f.meta.insert("rtmp".to_string(), "true".to_string());
                }

                for (k, v) in &query {
                    f.meta.insert(k.to_string(), v.to_string());
                }

                formats.push(f);
            } else {
                debug!("no metadata found for itag: {}, skipping...", itag)
            }
        }
    }

    video_info.formats = formats;
    Ok(video_info)
}

fn download() {

}

fn parse_query(query_str: String) -> HashMap<String, String> {
    let parse_query = form_urlencoded::parse(query_str.as_bytes());
    return parse_query.into_owned().collect::<HashMap<String, String>>();
}

fn get_client() -> Result<Client, Box<Error>> {
    let proxy_url = env::var(super::YTDL_PROXY_URL)?;
    let client: Client;
    if proxy_url.is_empty() {
        client = request::Client::new()?;
    } else {
        client = request::Client::builder()?
            .proxy(request::Proxy::all(proxy_url.as_str())?)
            .build()?;
    }

    Ok(client)
}<commit_msg>feat: get proxy client<commit_after>use std::error::Error;
use std::collections::HashMap;
use std::io::Read;
use std::env;

use url::{Url, form_urlencoded};
use url::percent_encoding::percent_decode;
use format::Format;
use reqwest::{self as request, StatusCode, Client};

#[derive(Serialize, Deserialize, Default)]
pub struct VideoInfo {
    pub id: String,
    pub describe: String,
    pub formats: Vec<Format>,
    pub keywords: Vec<String>,
    pub author: String,
    pub duration: i32,
}

impl VideoInfo {
    pub fn get_download_url(&self, f: &Format) -> Result<Url, Box<Error>> {
        let sig = f.meta.get("sig").map(|s| s.as_str()).unwrap_or_default();
        let url_str = if let Some(u) = f.meta.get("url") {
            u.as_str()
        } else {
            return Err(From::from("couldn't extract url from format"));
        };

        let url_str = percent_decode(url_str.as_bytes()).decode_utf8()?.into_owned();
        let mut parse_url = Url::parse(&url_str)?;
        parse_url.query_pairs_mut().append_pair("ratebypass", "yes");
        if !sig.is_empty() {
            parse_url.query_pairs_mut().append_pair("signature", sig);
        }

        Ok(parse_url)
    }
}

const YOUTUBE_VIDEO_INFO_URL: &str = "https://www.youtube.com/get_video_info";

pub fn get_video_info(value: &str) -> Result<VideoInfo, Box<Error>> {
    let parse_url = match Url::parse(value) {
        Ok(u) => u,
        Err(_) => {
            return get_video_info_from_html(value);
        },
    };

    if parse_url.host_str() == Some("youtu.be") {
        return get_video_info_from_short_url(&parse_url);
    }

    get_video_info_from_url(&parse_url)
}

fn get_video_info_from_url(u: &Url) -> Result<VideoInfo, Box<Error>> {
    if let Some(video_id) = u.query_pairs().into_owned().collect::<HashMap<String, String>>().get("v") {
        return get_video_info_from_html(video_id);
    }
    Err(From::from("invalid youtube url, no video id"))
}

fn get_video_info_from_short_url(u: &Url) -> Result<VideoInfo, Box<Error>> {
    let path = u.path().trim_left_matches("/");
    if path.len() > 0 {
        return get_video_info_from_html(path);
    }

    Err(From::from("could not parse short URL"))
}

fn get_video_info_from_html(id: &str) -> Result<VideoInfo, Box<Error>> {
    let info_url = format!("{}?video_id={}", YOUTUBE_VIDEO_INFO_URL, id);
    debug!("{}", info_url);
    let mut resp = get_client()?.get(info_url.as_str())?.send()?;
    if resp.status() != StatusCode::Ok {
        return Err(From::from("video info response invalid status code"));
    }

    let mut info = String::new();
    resp.read_to_string(&mut info)?;
    let info = parse_query(info);
    let mut video_info: VideoInfo = Default::default();
    match info.get("status") {
        Some(s) => {
            if s == "fail" {
                return Err(From::from(format!(
                    "Error {}:{}",
                    info.get("errorcode").map(|s| s.as_str()).unwrap_or_default(),
                    info.get("reason").map(|s| s.as_str()).unwrap_or_default()
                )));
            }
        },
        None => {
            return Err(From::from("get video info, status not found"));
        }
    };

    if let Some(author) = info.get("author") {
        video_info.author = author.to_string();
    } else {
        debug!("unable to extract author");
    }

    if let Some(length) = info.get("length_seconds") {
        video_info.duration = length.parse::<i32>().unwrap_or_default();
    } else {
        debug!("unable to parse duration string");
    }

    if let Some(keywords) = info.get("keywords") {
        video_info.keywords = keywords.split(",").map(|s| s.to_string()).collect();
    } else {
        debug!("unable to extract keywords")
    }

    let mut format_strings = vec![];
    if let Some(fmt_stream) = info.get("url_encoded_fmt_stream_map") {
        format_strings.append(&mut fmt_stream.split(",").collect())
    }

    if let Some(adaptive_fmts) = info.get("adaptive_fmts") {
        format_strings.append(&mut adaptive_fmts.split(",").collect());
    }

    let mut formats: Vec<Format> = vec![];
    for v in &format_strings {
        let query = parse_query(v.to_string());
        let itag = match query.get("itag") {
            Some(i) => i,
            None => {
                continue;
            }
        };

        if let Ok(i) = itag.parse::<i32>() {
            if let Some(mut f) = Format::new(i) {
                if query.get("conn").map(|s| s.as_str()).unwrap_or_default().starts_with("rtmp") {
                    f.meta.insert("rtmp".to_string(), "true".to_string());
                }

                for (k, v) in &query {
                    f.meta.insert(k.to_string(), v.to_string());
                }

                formats.push(f);
            } else {
                debug!("no metadata found for itag: {}, skipping...", itag)
            }
        }
    }

    video_info.formats = formats;
    Ok(video_info)
}

fn download() {

}

fn parse_query(query_str: String) -> HashMap<String, String> {
    let parse_query = form_urlencoded::parse(query_str.as_bytes());
    return parse_query.into_owned().collect::<HashMap<String, String>>();
}

fn get_client() -> Result<Client, Box<Error>> {
    let client: Client;
    if let Ok(u) = env::var(super::YTDL_PROXY_URL) {
        client = request::Client::builder()?
            .proxy(request::Proxy::all(u.as_str())?)
            .build()?;
    } else {
        client = request::Client::new()?;
    }

    Ok(client)
}<|endoftext|>


<commit_before>// Integration tests for cargo-fmt.

use std::env;
use std::path::Path;
use std::process::Command;

/// Run the cargo-fmt executable and return its output.
fn cargo_fmt(args: &[&str]) -> (String, String) {
    let mut bin_dir = env::current_exe().unwrap();
    bin_dir.pop(); // chop off test exe name
    if bin_dir.ends_with("deps") {
        bin_dir.pop();
    }
    let cmd = bin_dir.join(format!("cargo-fmt{}", env::consts::EXE_SUFFIX));

    // Ensure cargo-fmt runs the rustfmt binary from the local target dir.
    let path = env::var_os("PATH").unwrap_or_default();
    let mut paths = env::split_paths(&path).collect::<Vec<_>>();
    paths.insert(0, bin_dir);
    let new_path = env::join_paths(paths).unwrap();

    match Command::new(&cmd).args(args).env("PATH", new_path).output() {
        Ok(output) => (
            String::from_utf8(output.stdout).expect("utf-8"),
            String::from_utf8(output.stderr).expect("utf-8"),
        ),
        Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
    }
}

macro_rules! assert_that {
    ($args:expr, $check:ident $check_args:tt) => {
        let (stdout, stderr) = cargo_fmt($args);
        if !stdout.$check$check_args {
            panic!(
                "Output not expected for cargo-fmt {:?}\n\
                 expected: {}{}\n\
                 actual stdout:\n{}\n\
                 actual stderr:\n{}",
                $args,
                stringify!($check),
                stringify!($check_args),
                stdout,
                stderr
            );
        }
    };
}

#[ignore]
#[test]
fn version() {
    assert_that!(&["--version"], starts_with("rustfmt "));
    assert_that!(&["--version"], starts_with("rustfmt "));
    assert_that!(&["--", "-V"], starts_with("rustfmt "));
    assert_that!(&["--", "--version"], starts_with("rustfmt "));
}

#[ignore]
#[test]
fn print_config() {
    assert_that!(
        &["--", "--print-config", "current", "."],
        contains("max_width = ")
    );
}

#[ignore]
#[test]
fn rustfmt_help() {
    assert_that!(&["--", "--help"], contains("Format Rust code"));
    assert_that!(&["--", "-h"], contains("Format Rust code"));
    assert_that!(&["--", "--help=config"], contains("Configuration Options:"));
}

#[test]
fn cargo_fmt_out_of_line_test_modules() {
    // See also https://github.com/rust-lang/rustfmt/issues/5119
    let expected_modified_files = [
        "tests/mod-resolver/test-submodule-issue-5119/src/lib.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub1.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub2.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub3/sub4.rs",
    ];
    let args = [
        "-v",
        "--check",
        "--manifest-path",
        "tests/mod-resolver/test-submodule-issue-5119/Cargo.toml",
    ];
    let (stdout, _) = cargo_fmt(&args);
    for file in expected_modified_files {
        let path = Path::new(file).canonicalize().unwrap();
        assert!(stdout.contains(&format!("Diff in {}", path.display())))
    }
}
<commit_msg>tests: ignore cargo fmt test for rust-lang/rust runs<commit_after>// Integration tests for cargo-fmt.

use std::env;
use std::path::Path;
use std::process::Command;

/// Run the cargo-fmt executable and return its output.
fn cargo_fmt(args: &[&str]) -> (String, String) {
    let mut bin_dir = env::current_exe().unwrap();
    bin_dir.pop(); // chop off test exe name
    if bin_dir.ends_with("deps") {
        bin_dir.pop();
    }
    let cmd = bin_dir.join(format!("cargo-fmt{}", env::consts::EXE_SUFFIX));

    // Ensure cargo-fmt runs the rustfmt binary from the local target dir.
    let path = env::var_os("PATH").unwrap_or_default();
    let mut paths = env::split_paths(&path).collect::<Vec<_>>();
    paths.insert(0, bin_dir);
    let new_path = env::join_paths(paths).unwrap();

    match Command::new(&cmd).args(args).env("PATH", new_path).output() {
        Ok(output) => (
            String::from_utf8(output.stdout).expect("utf-8"),
            String::from_utf8(output.stderr).expect("utf-8"),
        ),
        Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
    }
}

macro_rules! assert_that {
    ($args:expr, $check:ident $check_args:tt) => {
        let (stdout, stderr) = cargo_fmt($args);
        if !stdout.$check$check_args {
            panic!(
                "Output not expected for cargo-fmt {:?}\n\
                 expected: {}{}\n\
                 actual stdout:\n{}\n\
                 actual stderr:\n{}",
                $args,
                stringify!($check),
                stringify!($check_args),
                stdout,
                stderr
            );
        }
    };
}

#[ignore]
#[test]
fn version() {
    assert_that!(&["--version"], starts_with("rustfmt "));
    assert_that!(&["--version"], starts_with("rustfmt "));
    assert_that!(&["--", "-V"], starts_with("rustfmt "));
    assert_that!(&["--", "--version"], starts_with("rustfmt "));
}

#[ignore]
#[test]
fn print_config() {
    assert_that!(
        &["--", "--print-config", "current", "."],
        contains("max_width = ")
    );
}

#[ignore]
#[test]
fn rustfmt_help() {
    assert_that!(&["--", "--help"], contains("Format Rust code"));
    assert_that!(&["--", "-h"], contains("Format Rust code"));
    assert_that!(&["--", "--help=config"], contains("Configuration Options:"));
}

#[ignore]
#[test]
fn cargo_fmt_out_of_line_test_modules() {
    // See also https://github.com/rust-lang/rustfmt/issues/5119
    let expected_modified_files = [
        "tests/mod-resolver/test-submodule-issue-5119/src/lib.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub1.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub2.rs",
        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub3/sub4.rs",
    ];
    let args = [
        "-v",
        "--check",
        "--manifest-path",
        "tests/mod-resolver/test-submodule-issue-5119/Cargo.toml",
    ];
    let (stdout, _) = cargo_fmt(&args);
    for file in expected_modified_files {
        let path = Path::new(file).canonicalize().unwrap();
        assert!(stdout.contains(&format!("Diff in {}", path.display())))
    }
}
<|endoftext|>


<commit_before>use std::os::unix::process::CommandExt;
use std::process::Command;

// clap exposes the macro value_t!
use clap::value_t;

// chrono needs this to call Local.datetime_from_str().
use chrono::offset::TimeZone;

const SQLITE3: &'static str = "/usr/bin/sqlite3";
const DB_PATH: &'static str = "/home/kalvin/Documents/personal/expenditures.db";

const PEREXP: &'static str = "perexp";
const ESSEXP: &'static str = "essexp";

const CLAP_AMOUNT: &'static str = "amount";
const CLAP_DESCRIPTION: &'static str = "description";
const CLAP_EXPENDITURE_TYPE: &'static str = "expenditure-type";
const CLAP_TARGET_DATE: &'static str = "target-date";

#[derive(Debug)]
pub enum ExpenditureType {
    Personal,
    Essential,
}

#[derive(Debug)]
pub struct SqlOptions {
    // Expenditure type is always required in transacting expenditures.
    expenditure_type: ExpenditureType,

    // Target date is always required in transacting expenditures.
    target_date: chrono::Date<chrono::Local>,

    // Amount and description are required for insertion.
    // They are meaningless for read-only queries.
    amount: Option<f64>,
    description: Option<String>,
}

#[derive(Debug)]
pub enum SqlCommand {
    Edit,
    Show(SqlOptions),
    Insert(SqlOptions),
}

mod from_clap {
    use super::*;

    pub fn expenditure_type(matches: &clap::ArgMatches) -> ExpenditureType {
        let symbolic_type = matches.value_of(CLAP_EXPENDITURE_TYPE).unwrap();

        match symbolic_type {
            "p" => return ExpenditureType::Personal,
            "e" => return ExpenditureType::Essential,
            _ => (),
        };
        panic!(format!(
            "invalid {} ``{}''",
            CLAP_EXPENDITURE_TYPE, symbolic_type
        ));
    }

    pub fn target_date(matches: &clap::ArgMatches) -> Option<chrono::Date<chrono::Local>> {
        if let Some(cli_target_date) = matches.value_of(CLAP_TARGET_DATE) {
            if let Ok(datetime) = chrono::Local.datetime_from_str(
                &format!("{} 00:00:00", cli_target_date).to_string(),
                "%Y-%m-%d %H:%M:%S",
            ) {
                return Some(datetime.date());
            }
            if let Ok(date_delta) = cli_target_date.parse::<i64>() {
                return Some((chrono::Local::now() - chrono::Duration::days(date_delta)).date());
            }
            panic!(format!("bad target date: ``{}''", cli_target_date));
        }
        None
    }

    pub fn amount(matches: &clap::ArgMatches) -> f64 {
        clap::value_t!(matches, CLAP_AMOUNT, f64).unwrap_or_else(|e| e.exit())
    }

    pub fn description(matches: &clap::ArgMatches) -> String {
        clap::value_t!(matches, CLAP_DESCRIPTION, String).unwrap_or_else(|e| e.exit())
    }
} // mod from_clap

fn build_show_options(matches: &clap::ArgMatches) -> SqlOptions {
    let target_date = match from_clap::target_date(matches) {
        Some(date) => date,
        // Aribtrary choice: peeks back 6 months.
        None => (chrono::Local::now() - chrono::Duration::days(183)).date(),
    };

    SqlOptions {
        expenditure_type: from_clap::expenditure_type(matches),
        target_date: target_date,
        amount: None,
        description: None,
    }
}

fn build_insert_options(matches: &clap::ArgMatches) -> SqlOptions {
    let target_date = match from_clap::target_date(matches) {
        Some(date) => date,
        None => chrono::Local::now().date(),
    };

    SqlOptions {
        expenditure_type: from_clap::expenditure_type(matches),
        target_date: target_date,
        amount: Some(from_clap::amount(matches)),
        description: Some(from_clap::description(matches)),
    }
}

fn parse_clap_matches(matches: clap::ArgMatches) -> SqlCommand {
    match matches.subcommand() {
        ("edit", _) => return SqlCommand::Edit,
        ("show", Some(show_matches)) => return SqlCommand::Show(build_show_options(show_matches)),
        ("insert", Some(insert_matches)) => {
            return SqlCommand::Insert(build_insert_options(insert_matches))
        }
        (&_, _) => panic!("no subcommand"),
    }
}

fn parse_command_line() -> SqlCommand {
    let matches = clap::App::new("tangerine-tailleferre")
        .version("0.1.0")
        .author("j39m")
        .about("manipulates expenditures")
        .subcommand(clap::App::new("edit").about("opens sqlite3 directly"))
        .subcommand(
            clap::App::new("show")
                .about("shows expenditures")
                .arg(
                    clap::Arg::with_name(CLAP_TARGET_DATE)
                        .takes_value(true)
                        .short("t"),
                )
                .arg(clap::Arg::with_name(CLAP_EXPENDITURE_TYPE).required(true)),
        )
        .subcommand(
            clap::App::new("insert")
                .about("inserts an expenditure")
                .arg(
                    clap::Arg::with_name(CLAP_AMOUNT)
                        .takes_value(true)
                        .required(true)
                        .short("a"),
                )
                .arg(
                    clap::Arg::with_name(CLAP_DESCRIPTION)
                        .takes_value(true)
                        .required(true)
                        .short("d"),
                )
                .arg(
                    clap::Arg::with_name(CLAP_TARGET_DATE)
                        .takes_value(true)
                        .short("t"),
                )
                .arg(clap::Arg::with_name(CLAP_EXPENDITURE_TYPE).required(true)),
        )
        .get_matches();

    parse_clap_matches(matches)
}

fn expenditure_type_name_from_enum(type_: &ExpenditureType) -> &'static str {
    match type_ {
        ExpenditureType::Personal => return PEREXP,
        ExpenditureType::Essential => return ESSEXP,
    }
}

fn build_show_command(options: SqlOptions) -> String {
    let wordy_display_command = format!(
        r#"select {} from {} where date >= date("{}");"#,
        "*",
        expenditure_type_name_from_enum(&options.expenditure_type),
        options.target_date.format("%Y-%m-%d").to_string()
    );
    let summation_command = format!(
        r#"select {} from {} where date >= date("{}");"#,
        "sum(amount)",
        expenditure_type_name_from_enum(&options.expenditure_type),
        options.target_date.format("%Y-%m-%d").to_string()
    );

    format!("{} {}", wordy_display_command, summation_command)
}

fn build_insert_command(options: SqlOptions) -> String {
    format!(
        r#"insert into {} values(date("{}"), "{}", {});"#,
        expenditure_type_name_from_enum(&options.expenditure_type),
        options.target_date.format("%Y-%m-%d"),
        options.description.unwrap(),
        options.amount.unwrap()
    )
}

fn build_extra_sqlite_arg() -> Option<String> {
    let sql_command = parse_command_line();

    match sql_command {
        SqlCommand::Edit => return None,
        SqlCommand::Show(options) => return Some(build_show_command(options)),
        SqlCommand::Insert(options) => return Some(build_insert_command(options)),
    };
}

fn main() {
    let mut command = Command::new(SQLITE3);
    command.arg(DB_PATH);

    if let Some(extra_arg) = build_extra_sqlite_arg() {
        command.arg(extra_arg);
    }

    eprintln!("{:#?}", command);
    command.exec();
}
<commit_msg>tt: use panic! formatter<commit_after>use std::os::unix::process::CommandExt;
use std::process::Command;

// clap exposes the macro value_t!
use clap::value_t;

// chrono needs this to call Local.datetime_from_str().
use chrono::offset::TimeZone;

const SQLITE3: &'static str = "/usr/bin/sqlite3";
const DB_PATH: &'static str = "/home/kalvin/Documents/personal/expenditures.db";

const PEREXP: &'static str = "perexp";
const ESSEXP: &'static str = "essexp";

const CLAP_AMOUNT: &'static str = "amount";
const CLAP_DESCRIPTION: &'static str = "description";
const CLAP_EXPENDITURE_TYPE: &'static str = "expenditure-type";
const CLAP_TARGET_DATE: &'static str = "target-date";

#[derive(Debug)]
pub enum ExpenditureType {
    Personal,
    Essential,
}

#[derive(Debug)]
pub struct SqlOptions {
    // Expenditure type is always required in transacting expenditures.
    expenditure_type: ExpenditureType,

    // Target date is always required in transacting expenditures.
    target_date: chrono::Date<chrono::Local>,

    // Amount and description are required for insertion.
    // They are meaningless for read-only queries.
    amount: Option<f64>,
    description: Option<String>,
}

#[derive(Debug)]
pub enum SqlCommand {
    Edit,
    Show(SqlOptions),
    Insert(SqlOptions),
}

mod from_clap {
    use super::*;

    pub fn expenditure_type(matches: &clap::ArgMatches) -> ExpenditureType {
        let symbolic_type = matches.value_of(CLAP_EXPENDITURE_TYPE).unwrap();

        match symbolic_type {
            "p" => return ExpenditureType::Personal,
            "e" => return ExpenditureType::Essential,
            _ => (),
        };
        panic!("invalid {} ``{}''", CLAP_EXPENDITURE_TYPE, symbolic_type);
    }

    pub fn target_date(matches: &clap::ArgMatches) -> Option<chrono::Date<chrono::Local>> {
        if let Some(cli_target_date) = matches.value_of(CLAP_TARGET_DATE) {
            if let Ok(datetime) = chrono::Local.datetime_from_str(
                &format!("{} 00:00:00", cli_target_date).to_string(),
                "%Y-%m-%d %H:%M:%S",
            ) {
                return Some(datetime.date());
            }
            if let Ok(date_delta) = cli_target_date.parse::<i64>() {
                return Some((chrono::Local::now() - chrono::Duration::days(date_delta)).date());
            }
            panic!("bad target date: ``{}''", cli_target_date);
        }
        None
    }

    pub fn amount(matches: &clap::ArgMatches) -> f64 {
        clap::value_t!(matches, CLAP_AMOUNT, f64).unwrap_or_else(|e| e.exit())
    }

    pub fn description(matches: &clap::ArgMatches) -> String {
        clap::value_t!(matches, CLAP_DESCRIPTION, String).unwrap_or_else(|e| e.exit())
    }
} // mod from_clap

fn build_show_options(matches: &clap::ArgMatches) -> SqlOptions {
    let target_date = match from_clap::target_date(matches) {
        Some(date) => date,
        // Aribtrary choice: peeks back 6 months.
        None => (chrono::Local::now() - chrono::Duration::days(183)).date(),
    };

    SqlOptions {
        expenditure_type: from_clap::expenditure_type(matches),
        target_date: target_date,
        amount: None,
        description: None,
    }
}

fn build_insert_options(matches: &clap::ArgMatches) -> SqlOptions {
    let target_date = match from_clap::target_date(matches) {
        Some(date) => date,
        None => chrono::Local::now().date(),
    };

    SqlOptions {
        expenditure_type: from_clap::expenditure_type(matches),
        target_date: target_date,
        amount: Some(from_clap::amount(matches)),
        description: Some(from_clap::description(matches)),
    }
}

fn parse_clap_matches(matches: clap::ArgMatches) -> SqlCommand {
    match matches.subcommand() {
        ("edit", _) => return SqlCommand::Edit,
        ("show", Some(show_matches)) => return SqlCommand::Show(build_show_options(show_matches)),
        ("insert", Some(insert_matches)) => {
            return SqlCommand::Insert(build_insert_options(insert_matches))
        }
        (&_, _) => panic!("no subcommand"),
    }
}

fn parse_command_line() -> SqlCommand {
    let matches = clap::App::new("tangerine-tailleferre")
        .version("0.1.0")
        .author("j39m")
        .about("manipulates expenditures")
        .subcommand(clap::App::new("edit").about("opens sqlite3 directly"))
        .subcommand(
            clap::App::new("show")
                .about("shows expenditures")
                .arg(
                    clap::Arg::with_name(CLAP_TARGET_DATE)
                        .takes_value(true)
                        .short("t"),
                )
                .arg(clap::Arg::with_name(CLAP_EXPENDITURE_TYPE).required(true)),
        )
        .subcommand(
            clap::App::new("insert")
                .about("inserts an expenditure")
                .arg(
                    clap::Arg::with_name(CLAP_AMOUNT)
                        .takes_value(true)
                        .required(true)
                        .short("a"),
                )
                .arg(
                    clap::Arg::with_name(CLAP_DESCRIPTION)
                        .takes_value(true)
                        .required(true)
                        .short("d"),
                )
                .arg(
                    clap::Arg::with_name(CLAP_TARGET_DATE)
                        .takes_value(true)
                        .short("t"),
                )
                .arg(clap::Arg::with_name(CLAP_EXPENDITURE_TYPE).required(true)),
        )
        .get_matches();

    parse_clap_matches(matches)
}

fn expenditure_type_name_from_enum(type_: &ExpenditureType) -> &'static str {
    match type_ {
        ExpenditureType::Personal => return PEREXP,
        ExpenditureType::Essential => return ESSEXP,
    }
}

fn build_show_command(options: SqlOptions) -> String {
    let wordy_display_command = format!(
        r#"select {} from {} where date >= date("{}");"#,
        "*",
        expenditure_type_name_from_enum(&options.expenditure_type),
        options.target_date.format("%Y-%m-%d").to_string()
    );
    let summation_command = format!(
        r#"select {} from {} where date >= date("{}");"#,
        "sum(amount)",
        expenditure_type_name_from_enum(&options.expenditure_type),
        options.target_date.format("%Y-%m-%d").to_string()
    );

    format!("{} {}", wordy_display_command, summation_command)
}

fn build_insert_command(options: SqlOptions) -> String {
    format!(
        r#"insert into {} values(date("{}"), "{}", {});"#,
        expenditure_type_name_from_enum(&options.expenditure_type),
        options.target_date.format("%Y-%m-%d"),
        options.description.unwrap(),
        options.amount.unwrap()
    )
}

fn build_extra_sqlite_arg() -> Option<String> {
    let sql_command = parse_command_line();

    match sql_command {
        SqlCommand::Edit => return None,
        SqlCommand::Show(options) => return Some(build_show_command(options)),
        SqlCommand::Insert(options) => return Some(build_insert_command(options)),
    };
}

fn main() {
    let mut command = Command::new(SQLITE3);
    command.arg(DB_PATH);

    if let Some(extra_arg) = build_extra_sqlite_arg() {
        command.arg(extra_arg);
    }

    eprintln!("{:#?}", command);
    command.exec();
}
<|endoftext|>


<commit_before>extern crate mpd;

use std::env;
use std::net::TcpStream;

pub fn connect() -> mpd::Client<TcpStream> {
    let addr = env::var("MPD_SOCK").unwrap_or("127.0.0.1:6600".to_owned());
    mpd::Client::connect(&*addr).unwrap()
}
<commit_msg>Don't call functions in `.unwrap_or`.<commit_after>extern crate mpd;

use std::env;
use std::net::TcpStream;

pub fn connect() -> mpd::Client<TcpStream> {
    let addr = env::var("MPD_SOCK").unwrap_or_else(|_| "127.0.0.1:6600".to_owned());
    mpd::Client::connect(&*addr).unwrap()
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate rustc_serialize;

use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn simple() {
    let p = project("foo");

    assert_that(p.cargo_process("version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

    assert_that(p.cargo_process("--version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

}

#[derive(RustcDecodable)]
struct FooFlags {
    flag_version: bool,
}

fn real_main(flags: FooFlags, _config: &cargo::Config) ->
        cargo::CliResult<Option<String>> {
    if flags.flag_version {
        Ok(Some("foo <version>".to_string()))
    } else {
        Ok(None)
    }
}

#[test]
fn subcommand_with_version_using_exec_main_without_stdin() {
    let usage = "
Usage: cargo foo [--version]

Options:
    -V, --version       Print version info
";
    let args: Vec<String> = vec!["cargo", "foo", "--version"]
        .into_iter().map(|s| s.to_string()).collect();
    let result = cargo::call_main_without_stdin(
                real_main, &cargo::Config::default().unwrap(),
                usage, &args, false);
    assert_eq!(result.unwrap(), Some("foo <version>".to_string()));
}

#[test]
fn version_works_without_rustc() {
    let p = project("foo");
    assert_that(p.cargo_process("version").env("PATH", ""),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_config() {
    let p = project("foo")
        .file(".cargo/config", "this is not toml");
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_target_dir() {
    let p = project("foo")
        .file(".cargo/config", r#"
            [build]
            target-dir = 4
        "#);
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}
<commit_msg>Auto merge of #3189 - edunham:fix-empty-path-bug, r=alexcrichton<commit_after>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate rustc_serialize;

use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn simple() {
    let p = project("foo");

    assert_that(p.cargo_process("version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

    assert_that(p.cargo_process("--version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

}

#[derive(RustcDecodable)]
struct FooFlags {
    flag_version: bool,
}

fn real_main(flags: FooFlags, _config: &cargo::Config) ->
        cargo::CliResult<Option<String>> {
    if flags.flag_version {
        Ok(Some("foo <version>".to_string()))
    } else {
        Ok(None)
    }
}

#[test]
fn subcommand_with_version_using_exec_main_without_stdin() {
    let usage = "
Usage: cargo foo [--version]

Options:
    -V, --version       Print version info
";
    let args: Vec<String> = vec!["cargo", "foo", "--version"]
        .into_iter().map(|s| s.to_string()).collect();
    let result = cargo::call_main_without_stdin(
                real_main, &cargo::Config::default().unwrap(),
                usage, &args, false);
    assert_eq!(result.unwrap(), Some("foo <version>".to_string()));
}

#[test]
#[cfg_attr(target_os = "windows", ignore)]
fn version_works_without_rustc() {
    let p = project("foo");
    assert_that(p.cargo_process("version").env("PATH", ""),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_config() {
    let p = project("foo")
        .file(".cargo/config", "this is not toml");
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_target_dir() {
    let p = project("foo")
        .file(".cargo/config", r#"
            [build]
            target-dir = 4
        "#);
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}
<|endoftext|>